C# 中經常使用的索引器

使用 C# 中的索引器和 JavaScript 中訪問對象的屬性是很類似。html

以前瞭解過索引器,當時還把索引器和屬性給記混了, 覺得索引器就是屬性,下面寫下索引器和屬性的區別,以及怎麼使用索引器數據庫

先說明一點,這裏的索引器和數據庫中的索引不同,雖然都是找元素。數組

索引器和屬性的區別:函數

  1. 屬性和索引器都是函數,可是表現形式不同;(屬性和索引器在代碼的表現形式上和函數不一致,但其本質都是函數,須要經過 ILDASM 來查看,或者使用反射
  2. 索引器能夠被重載,而屬性沒有重載這一說法;(索引器的重載即方括號中的類型不一樣
  3. 索引器不能聲明爲static,而屬性能夠;(索引器之因此不能聲明爲 static,由於其自身攜帶 this 關鍵字,須要被對象調用

還有一點就是索引很像數組,它容許一個對象能夠像數組同樣被中括號 [] 索引,可是和數組有區別,具體有:工具

  1. 數組的角標只能是數字,而索引器的角標能夠是數字也能夠是引用類型;
  2. 數組是一個引用類型的變量,而索引器是一個函數;

      我在代碼中不多本身定義索引器,可是我卻常常在用它,那是由於系統自定義了不少索引器,好比 ADO.NET 中對於 DataTable 和 DataRow 等類的各類遍歷,查找,不少地方就是用的索引器,好比下面這篇博客中的代碼就使用了不少系統自定義的索引器:this

DataTable的AcceptChanges()方法和DataRow的RowState屬性 (其中索引器的使用都以及註明,)spa

 

那咱們如何自定索引器? 回到這篇博客第一句話,我曾經把索引器和屬性弄混過,那就說明他倆很像,看下代碼看是否是很像:3d

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Dynamic;
//這裏的代碼時參照自http://www.cnblogs.com/ArmyShen/archive/2012/08/27/2659405.html的代碼片斷
namespace Demo1
{
    public class IndexerClass
    {
        private string[] name = new string[2];
        //索引器必須以this關鍵字定義,其實這個this就是類實例化以後的對象
        public string this[int index]
        {
            //實現索引器的get方法
            get
            {
                if (index >= 0 && index < 2)
                {
                    return name[index];
                }
                return null;
            }
            //實現索引器的set方法
            set
            {
                if (index >= 0 && index < 2)
                {
                    name[index] = value;
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
          //索引器的使用
            IndexerClass Indexer = new IndexerClass();
          //「=」號右邊對索引器賦值,其實就是調用其set方法
            Indexer[0] = "張三";
          Indexer[1] = "李四";
          //輸出索引器的值,其實就是調用其get方法
            Console.WriteLine(Indexer[0]);
          Console.WriteLine(Indexer[1]);
        }
    }
}

      乍一眼看上去,感受和屬性差很少了, 可是仔細一看,索引器沒有名稱,有對方括號,並且多了 this 關鍵字,看到這裏的 this 的特殊用法又讓我想到了擴展方法中的 this的特殊位置。code

      上面再講索引和屬性的區別時,說到了索引其實也是函數,證實索引器是函數,我在上面的的代碼中加入了一個普通方法 Add,htm

public class IndexerClass
    {
        public string[] strArr = new string[2];
        //一個屬性
        public int Age { get; set; }
        //一個方法
        public int Add(int a,int b)
        {
            return a + b;
        }
        //一個索引器
        public string this[int index]
        {
            get
            {
                if (index < 2 && index >= 0)
                    return strArr[index];
                return null;
            }
            set
            {
                if (index >= 0 && index < 2)
                {
                    strArr[index] = value;
                }
            }
        }
    }

     咱們將程序從新編譯一下,而後使用 ILDASM 工具查看下編譯出來的 .exe 文件,以下圖:

image

      從中咱們能夠看到一個 Add 的方法,image這個小圖標表明着方法,一共有 6 個方法,其中 .ctor 暫時無論,Add 方法是咱們本身寫的,

get_Age : int32(),這個方法是屬性 age 的讀方法,對應的還有個寫方法;

還剩下兩個就是索引器生成的方法了,get_Item:string(int32) 和 set_Item : void(int32) ;

還有這樣的圖標image,這個圖標是表明着字段,上面的兩個字段是自動生成的,這也是 C#中的語法糖了,不用聲明字段,只用聲明屬性,編譯器會自動生成相應字段。

關於 C# 的語法糖能夠點擊這篇博客C# 中的語法糖

關於 ILDASM 的安裝與使用能夠點擊這篇博客ILDASM 的添加和使用

以字符串爲角標, 這點就和數組不同了:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Dynamic;
using System.Collections;
//這裏的代碼時參照自http://www.cnblogs.com/ArmyShen/archive/2012/08/27/2659405.html的代碼片斷 
namespace Demo1
{
    public class IndexerClass
    {
        //用string做爲索引器下標的時候,要用Hashtable
        private Hashtable name = new Hashtable();
        //索引器必須以this關鍵字定義,其實這個this就是類實例化以後的對象
        public string this[string index]
        {
            get { return name[index].ToString(); }
            set { name.Add(index, value); }    
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IndexerClass Indexer = new IndexerClass();
            Indexer["A0001"] = "張三";
            Indexer["A0002"] = "李四";
            Console.WriteLine(Indexer["A0001"]);
            Console.WriteLine(Indexer["A0002"]);
        }
    }
}

 

索引器的重載,這點就是屬性的不一樣:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Dynamic;
using System.Collections;
//這裏的代碼時參照自http://www.cnblogs.com/ArmyShen/archive/2012/08/27/2659405.html的代碼片斷 
namespace Demo1
{
    public class IndexerClass
    {
        private Hashtable name = new Hashtable();
        //1:經過key存取Values
        public string this[int index]
        {
            get { return name[index].ToString(); }
            set { name.Add(index, value); }
        }

        //2:經過Values存取key
        public int this[string aName]
        {
            get
            {
                //Hashtable中實際存放的是DictionaryEntry(字典)類型,若是要遍歷一個Hashtable,就須要使用到DictionaryEntry
                foreach (DictionaryEntry d in name)
                {
                    if (d.Value.ToString() == aName)
                    {
                        return Convert.ToInt32(d.Key);
                    }
                }
                return -1;
            }
            set { name.Add(value, aName); }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IndexerClass Indexer = new IndexerClass();
            //第一種索引器的使用
             Indexer[1] = "張三";//set訪問器的使用
             Indexer[2] = "李四";
           Console.WriteLine("編號爲1的名字:" + Indexer[1]);//get訪問器的使用
             Console.WriteLine("編號爲2的名字:" + Indexer[2]);
           Console.WriteLine();
           //第二種索引器的使用
             Console.WriteLine("張三的編號是:" + Indexer["張三"]);//get訪問器的使用
             Console.WriteLine("李四的編號是:" + Indexer["李四"]);
           Indexer["王五"] = 3;//set訪問器的使用
             Console.WriteLine("王五的編號是:" + Indexer["王五"]);
        }
    }
}

 

具備多個參數的索引器:

using System;
using System.Collections;
//這裏的代碼時參照自http://www.cnblogs.com/ArmyShen/archive/2012/08/27/2659405.html的代碼片斷 
namespace Demo1
{
    /// <summary>
    /// 入職信息類
    /// </summary>
    public class EntrantInfo
    {
        //姓名、編號、部門
        public string Name { get; set; }
        public int Num { get; set; }
        public string Department { get; set; }
    }

    /// <summary>
    /// 聲明一個類EntrantInfo的索引器
    /// </summary>
    public class IndexerForEntrantInfo
    {
        private ArrayList ArrLst;//用於存放EntrantInfo類
        public IndexerForEntrantInfo()
        {
            ArrLst = new ArrayList();
        }

        /// <summary>
        /// 聲明一個索引器:以名字和編號查找存取部門信息
        /// </summary>
        /// <param name="name"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public string this[string name, int num]
        {
            get
            {
                foreach (EntrantInfo en in ArrLst)
                {
                    if (en.Name == name && en.Num == num)
                    {
                        return en.Department;
                    }
                }
                return null;
            }
            set
            {
                ArrLst.Add(new EntrantInfo()
                {
                    Name = name,
                    Num= num,
                    Department = value
                });
            }
        }

        /// <summary>
        /// 聲明一個索引器:以編號查找名字和部門
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public ArrayList this[int num]
        {
            get
            {
                ArrayList temp = new ArrayList();
                foreach (EntrantInfo en in ArrLst)
                {
                    if (en.Num == num)
                    {
                        temp.Add(en);
                    }
                }
                return temp;
            }
        }
        //還能夠聲明多個版本的索引器...
    }

    class Program
    {
        static void Main(string[] args)
        {
            IndexerForEntrantInfo Info = new IndexerForEntrantInfo();
            //this[string name, int num]的使用
             Info["張三", 101] = "人事部";
            Info["李四", 102] = "行政部";
            Console.WriteLine(Info["張三", 101]);
            Console.WriteLine(Info["李四", 102]);
            Console.WriteLine();
            //this[int num]的使用
            foreach (EntrantInfo en in Info[102])
            {
                Console.WriteLine(en.Name);
                Console.WriteLine(en.Department);
            }
        }
    }
}
相關文章
相關標籤/搜索