zoukankan      html  css  js  c++  java
  • 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);
                }
            }
        }
    }
  • 相关阅读:
    Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse. ......
    UVA 1597 Searching the Web
    UVA 1596 Bug Hunt
    UVA 230 Borrowers
    UVA 221 Urban Elevations
    UVA 814 The Letter Carrier's Rounds
    UVA 207 PGA Tour Prize Money
    UVA 1592 Database
    UVA 540 Team Queue
    UVA 12096 The SetStack Computer
  • 原文地址:https://www.cnblogs.com/daimajun/p/6819081.html
Copyright © 2011-2022 走看看