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);
                }
            }
        }
    }
  • 相关阅读:
    网络需求分析课堂作业
    工程招标与投标课堂作业
    burpsuite Pro下载安装及破解 | JDK安装和配置
    渗透测试环境的搭建
    web应用基础架构
    为Linux环境安装图形化界面
    Linux基本操作
    markdown语法教程(更新中)
    VMware导入和删除虚拟机文件
    Java求幂集与List的浅拷贝深拷贝问题
  • 原文地址:https://www.cnblogs.com/superfeeling/p/11650605.html
Copyright © 2011-2022 走看看