C# 中常用的索引器


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

之前了解過索引器,當時還把索引器和屬性給記混了, 以為索引器就是屬性,下面寫下索引器和屬性的區別,以及怎么使用索引器

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

索引器和屬性的區別:

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

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

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

      我在代碼中很少自己定義索引器,但是我卻經常在用它,那是因為系統自定義了很多索引器,比如 ADO.NET 中對於 DataTable 和 DataRow 等類的各種遍歷,查找,很多地方就是用的索引器,比如下面這篇博客中的代碼就使用了很多系統自定義的索引器:

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

 

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

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的特殊位置。

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

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);
            }
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM