Understand and use C # indexer

Outline

This section is quoted from MSDN documentation

  • Using an index can be used in a manner similar to index an array of objects.

  • getValue function return value. setValue assignment function value.

  • this Keyword is used to define the indexers.

  • valueKeyword is used to define the setvalue of the index is being assigned.

  • Index does not have to be indexed by integer values; you decide how to define a specific lookup mechanism.

  • Index may be overloaded.

  • Index may have zero or more parameters, for example, when accessing a two-dimensional array.

I understand indexer is that he is an interface to read and write data from a defined set of classes, the data connection from the defined set of classes, and can read and write to

Through this interface simplified or rich operation mode from the set of data defining the class

Index actually equivalent to a method, a plurality of supports and a plurality of types of parameters, except that its value can not be returned void, and the parameters can be passed in addition to the indexer, it can also be assigned, i.e.,it[0] = "测试数据0"

Creating an index, a type of return value also for valuethe type of keyword is used, i.e., simultaneously defines the type of the return value, also defines the types of acceptable values

The indexer uses elements

    There are several parts content is necessary when creating an index is:

  1. You must create the required indexer container (I call it the container, being not see a specific definition of it)

  2. Creating an index requires the use of thiskeywords

  3. Indexer must be included getand setaccess devices, in C # 7.0 can use the expression main ( =>) simplifies

  4. When using expressions to achieve the main members of the index, you must modify the interface to provide additional container, because the body through the index expressions realize that does not contain setkeywords

Single parameter indexer

    This index uses a simple stringarray as a container, uses this index inttype iindex, return value stringtype.

class SampleIndxer
{
    //可供索引器使用的容器,暂用数组
    private string[] sampleStrArr = new string[10];
    //创建索引器
    public string this[int i]
    {
        get { return sampleStrArr[i]; }
        set { sampleStrArr[i] = value; }
    }
}
class Test
{
    public static void test()
    {
        //简单索引器测试
        SampleIndxer it = new SampleIndxer();
        it[0] = "测试数据0";
        it[1] = "测试数据1";
        Console.WriteLine("it[0]:" + it[0]);
        Console.WriteLine("it[1]:" + it[1]);
        Console.ReadLine();
    }

}

    Indexer and can also be used as a generic parameter

class SampleGenericIndexer<T>
{
    //可供索引器使用的主体变量,暂用泛型数组代替
    private T[] sampleGenericStrArr = new T[10];
    public T this[int i]
    {
        get { return sampleGenericStrArr[i]; }
        set { sampleGenericStrArr[i] = value; }
    }
}


class Test
{
    public static void test()
    {
        //泛型索引器测试
        SampleGenericIndexer<string> it = new SampleGenericIndexer<string>();
        it[0] = "测试数据0";
        it[1] = "测试数据1";
        Console.WriteLine("it[0]:" + it[0]);
        Console.WriteLine("it[1]:" + it[1]);
        Console.ReadLine();
    }
}

    In 7.0 C # after by the expression body to achieve indexer, it should be noted that, by the expression body when implementing an index, you must provide the data modification interface, because by the expression body when implementing an index only provides getaccess control, and It does not provide setaccess control. Or the container may be used for local access class setting may access, operate directly on the data container, using only the data read indexer.

class ExpressionBodyIndexer<T>
{
    //可供索引器使用的主体变量,暂用泛型数组代替
    private T[] expressionBodyStrArr = new T[10];

    //标记当前索引器的中已初始化数据的索引位置
    int nextIndex = 0;
    // 使用表达式主体(ExpressionBody)定义简化定义索引器
    public T this[int i] => expressionBodyStrArr[i];

    /// <summary>
    /// 表达式主体方式定义的索引器无法通过索引值设置其中的值
    /// 因为此状态下,索引器的数据为只读状态
    /// 必须向外提供赋值的方法
    /// </summary>
    /// <param name="value"></param>
    public void Add(T value)
    {
        if(nextIndex >= expressionBodyStrArr.Length)
        {
            throw new IndexOutOfRangeException($"当前集合数据已满,共{expressionBodyStrArr.Length}组数据");
        }
        expressionBodyStrArr[nextIndex++] = value;
    }
}
class Test
{
    public static void test()
    {
        //泛型索引器测试
        ExpressionBodyIndexer<string> it = new ExpressionBodyIndexer<string>();
        //此条件下不可通过it[0]索引方式进行数据添加,因为他是只读的
        //必须通过提供的Add方法添加数据
        it.Add("测试数据0");
        it.Add("测试数据1");
        it.Add("测试数据2");
        Console.WriteLine("it[0]:" + it[0]);
        Console.WriteLine("it[1]:" + it[1]);
        Console.WriteLine("it[2]:" + it[2]);
        Console.ReadLine();
    }
}

    Since it is possible to simplify the indexer or rich operation mode from the set of data defining the class, then the data can naturally also be used slightly more complex set of containers as indexer. This embodiment is used as a container Dictionary.

class VariableLengthIndexer
{
    /// <summary>
    /// 可供索引器使用的容器,此处使用Dictionary代替,

    /// 实现使用string类型数据当作索引器的指针,同时实现索引器的可变长度
    /// </summary>
    private Dictionary<string, string> dic = new Dictionary<string, string>();

    /// <summary>
    /// 使用表达式主体创建索引器
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public string this[string s] => dic[s];
    
    public void Add(string key,string value)
    {
        if (dic.ContainsKey(key))
        {
            dic[key] = value;
        }
        else
        {
            dic.Add(key, value);
        }
    }
}
class Test
{
    public static void test()
    {
        //泛型索引器测试
        VariableLengthIndexer it = new VariableLengthIndexer();
        //此条件下不可通过it[0]索引方式进行数据添加,因为他是只读的
        //必须通过提供的Add方法添加数据
        it.Add("数据0", "测试数据0");
        it.Add("数据1", "测试数据1");
        it.Add("数据2", "测试数据2");
        Console.WriteLine("it[数据1]:" + it["数据1"]);
        Console.WriteLine("it[数据2]:" + it["数据2"]);
        Console.WriteLine("it[数据3]:" + it["数据3"]);
        Console.ReadLine();
    }
}

    Some examples of the foregoing, only for the understanding of the indexer, the actual value is not used and the work, because the operation can be done entirely in .NET predefined data collection is completed. Personally I think 7.0 C # provides the following expression main practical effect is not large, it is not necessary even. Personally think that there is a maximum value of the index is in getand setfor custom data processing operations, the data can be corrected or filter in the accessor accessor, this is reflected in its relatively good value.

    Indexer made by encapsulation of the data processing, usually most of the operations can be simplified, such access may also be embedded in the database according to the actual situation of the entity classes.

/// <summary>
/// 本实例通过考试成绩的处理演示索引器对数据处理的过程
/// </summary>
class TestScore
{
    private Dictionary<string, int> scores = new Dictionary<string, int>();

    public string this[string s]
    {
        get
        {
            if (!scores.ContainsKey(s))
            {
                return $"非常抱歉,{s}的成绩尚未录入";
            }
            switch (scores[s])
            {
                case 10:
                case 20:
                case 30:
                case 40:
                case 50:
                    return $"很遗憾,{s}不及格,分数仅为{scores[s]}";
                case 60:
                case 70:
                    return $"考的不错,{s}已及格,分数为{scores[s]}";
                case 80:
                case 90:
                    return $"成绩优秀,{s}成绩优秀,分数为{scores[s]}";
                case 100:
                    return $"非常优秀,{s}获取满分{scores[s]}分";
                default:
                    return $"{s}的成绩可能存在异常,分数为{scores[s]}";
            }
        }
        set
        {
            if (int.TryParse(value, out int v))
            {
                //对分数做四舍五入处理
                v = (int)Math.Round(v * 0.1) * 10;

                if (!scores.ContainsKey(s))
                {
                    scores.Add(s, v);
                }
                else
                {
                    scores[s] = v;
                }
            }
        }
    }
}

class Test
{
    public static void test()
    {
        TestScore ts = new TestScore();
        ts["张三"] = "23";
        ts["李四"] = "54";
        ts["王二"] = "66";
        ts["麻子"] = "89";
        ts["王朝"] = "100";
        ts["马汉"] = "5";
        ts["老王"] = "";

        Console.WriteLine(ts["张三"]);
        Console.WriteLine(ts["李四"]);
        Console.WriteLine(ts["王二"]);
        Console.WriteLine(ts["麻子"]);
        Console.WriteLine(ts["王朝"]);
        Console.WriteLine(ts["马汉"]);
        Console.WriteLine(ts["老王"]);
        Console.ReadLine();

    }
}

Multi-parameter indexer

    So in front of a single parameter to achieve its analysis of the use of an index that is possible using a range of simple to expand at below, use multi-parameter analysis of the indexer, the score still use the above examples make presentations.

struct Student
{
    public string Name;
    public string Classes;
    public string Grade;
    public int Score;
        
    public override string ToString()
    {
        return $"{this.Grade}\t{this.Classes}\t{this.Name}\t{this.Score}";
    }
}

public class ArrayList1 : ArrayList
{
    public override bool Contains(object item)
    {
        if (item.GetType().ToString() == "Student")
        {
            foreach (var a in this)
            {
                if (a.GetType().ToString() == "Student")
                {
                    var s1 = (Student)a;
                    var s2 = (Student)item;
                    if (s1.Name == s2.Name && s1.Classes == s2.Classes && s1.Grade == s2.Grade)
                    {
                        return true;
                    }
                    return false;
                }
            }
        }
        return base.Contains(item);
    }
}

class TestScore
{
    public ArrayList1 ArrList = new ArrayList1();

    public string this[string name, string grade, string classes]
    {
        get
        {
            string rtn = "";
            foreach (Student a in ArrList)
            {
                if (a.Name == name && a.Classes == classes && a.Grade == grade)
                {
                    switch (a.Score)
                    {
                        case 10:
                        case 20:
                        case 30:
                        case 40:
                        case 50:
                            rtn = $"很遗憾,{name}不及格,分数仅为{a.Score}";
                            break;
                        case 60:
                        case 70:
                            rtn = $"考的不错,{name}已及格,分数为{a.Score}";
                            break;
                        case 80:
                        case 90:
                            rtn = $"成绩优秀,{name}成绩优秀,分数为{a.Score}";
                            break;
                        case 100:
                            rtn = $"非常优秀,{name}获取满分{a.Score}分";
                            break;
                        default:
                            rtn = $"{name}的成绩可能存在异常,分数为{a.Score}";
                            break;
                    }
                }
            }
            if (rtn == "")
            {
                return $"非常抱歉,{name}的成绩尚未录入";
            }
            return rtn;
        }
        set
        {
            if (int.TryParse(value, out int v))
            {
                //对分数做四舍五入处理
                v = (int)Math.Round(v * 0.1) * 10;

                Student st = new Student
                {
                    Name = name,
                    Grade = grade,
                    Classes = classes,
                    Score = v
                };
                //重复项,不再插入,避免查找时出现重复
                if (!ArrList.Contains(st))
                {
                    ArrList.Add(st);
                }
            }
        }
    }
}

class Test
{
    public static void test()
    {
        TestScore ts = new TestScore();
        ts["张三", "三年级", "二班"] = "23";
        ts["李四", "三年级", "二班"] = "54";
        ts["王二", "三年级", "二班"] = "66";
        ts["麻子", "三年级", "二班"] = "89";
        ts["王朝", "三年级", "二班"] = "100";
        ts["马汉", "三年级", "二班"] = "5";
        ts["老王", "三年级", "二班"] = "";
        Console.WriteLine("查看存入的数据:");
        Console.WriteLine($"共存入了:{ts.ArrList.Count}组数据");
        Console.WriteLine();
        //不使用索引器,直接访问实例中的容器

        foreach (Student s in ts.ArrList)
        {
            Console.WriteLine(s.ToString());
        }
        Console.WriteLine();

        Console.WriteLine(ts["张三", "三年级", "二班"]);
        Console.WriteLine(ts["李四", "三年级", "二班"]);
        Console.WriteLine(ts["王二", "三年级", "二班"]);
        Console.WriteLine(ts["麻子", "三年级", "二班"]);
        Console.WriteLine(ts["王朝", "三年级", "二班"]);
        Console.WriteLine(ts["马汉", "三年级", "二班"]);
        Console.WriteLine(ts["老王", "三年级", "二班"]);
        Console.ReadLine();

    }
}

    While achieving a two-dimensional array of multiple parameters, also supports two-dimensional array

public string[,] sampleStrArr = new string[10,10];
public string this[int x,int y]
{
    get { return sampleStrArr[x, y]; }
    set { sampleStrArr[x, y] = value; }
}

public static void test()
{
    SampleIndxer it = new SampleIndxer();
    it[0, 0] = "测试数据0,0";
    it[0, 1] = "测试数据0,1";
    it[1, 1] = "测试数据1,1";
    it[1, 2] = "测试数据1,2";
    it[3, 3] = "测试数据3,3";

    Console.WriteLine("it[0,0]:" + it[0, 0]);
    Console.WriteLine("it[0,1]:" + it[0, 1]);
    Console.WriteLine("it[1,1]:" + it[1, 1]);
    Console.WriteLine("it[1,2]:" + it[1, 2]);
    Console.WriteLine("it[3,3]:" + it[3, 3]);

    Console.ReadLine();
}

Indexer overload

    As mentioned above, the index is equivalent to a method, they also support the heavy load. Different methods and is independent of the name of the index is not only to distinguish the different signatures returned by different parameters and different values, in order to achieve overload.

class VariableLengthIndexer
{
    private Dictionary<string, int> dic = new Dictionary<string, int>();

    //通过Key,查找Value
    public int this[string s]
    {
        get { return dic[s]; }
    }
    //通过Value查找Key
    public string this[int num]
    {
        get { return dic.Where(x => x.Value == num).Last().Key; }
    }
    //通过Value查找Key,添加无效参数num1演示重载
    public string this[int num, int num1]
    {
        get { return dic.Where(x => x.Value == num).Last().Key; }
    }

    public void Add(string key, int value)
    {
        if (dic.ContainsKey(key))
        {
            dic[key] = value;
        }
        else
        {
            dic.Add(key, value);
        }
    }
}
class Test
{
    public static void test()
    {
        //泛型索引器测试
        VariableLengthIndexer it = new VariableLengthIndexer();
        it.Add("测试数据1", 1);
        it.Add("测试数据2", 2);
        it.Add("测试数据3", 3);
        it.Add("测试数据4", 4);
        //通过Key查找Value
        Console.WriteLine("通过Key查找Value");
        Console.WriteLine("Key:测试数据1,Value:" + it["测试数据1"]);
        Console.WriteLine("Key:测试数据2,Value:" + it["测试数据2"]);
        Console.WriteLine("Key:测试数据3,Value:" + it["测试数据3"]);
        Console.WriteLine("Key:测试数据4,Value:" + it["测试数据4"]);
        //通过Value查找Key
        Console.WriteLine("通过Value查找Key");
        Console.WriteLine("Value:1,Key:" + it[1]);
        Console.WriteLine("Value:2,Key:" + it[2]);
        Console.WriteLine("Value:3,Key:" + it[3]);
        Console.WriteLine("Value:4,Key:" + it[4]);
        //通过Value查找Key,并添加无效参数传入
        Console.WriteLine("通过Value查找Key,并添加无效参数传入");
        Console.WriteLine("Value:1,Key:" + it[1, 1]);
        Console.WriteLine("Value:2,Key:" + it[2, 2]);
        Console.WriteLine("Value:3,Key:" + it[3, 3]);
        Console.WriteLine("Value:4,Key:" + it[4, 4]);

        Console.ReadLine();
    }
}

references:

. 1 C # commonly indexer https://www.cnblogs.com/daimajun/p/6819081.html

2 Indexers (C # Programming Guide) https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/indexers/

Guess you like

Origin www.cnblogs.com/Hope-forever/p/12113842.html