c#索引器
1.索引器概述
c#中的索引器提供了语法的简洁方便的特性,它允许你访问对象元素如同访问数组那样,通常我们会在实现索引器的类的内部维护一个内部的集合或数组,通过索引器来实现对集合中的元素的存取操作。例如,我定义了一个row对象,内部维护了column数组,我们访问通过数组的方式访问row就相当于访问了对应的column元素,一目了然。代码如下:
public class Row { private string[] _column; public int Age { get; set; } public Row(int len) { _column = new string[len]; } public string this[int index] { get { return _column[index]; } set { _column[index] = value; } } } //测试代码: class Program { static void Main(string[] args) { Row r = new Row(10); for (int i = 0; i < 10; i++) { r[i] = i.ToString(); } for (int i = 0; i < 10; i++) { Console.WriteLine("row["+i+"]="+r[i]); } } }
程序运行的结果:
2.索引器的背后机制:
通过上面的代码的例子我们需要知道访问row[0]是究竟编译器帮我们在背后做了什么,同ildasm可以看到编译器为我们多生成了两个方法,一个是set_Item,一个是get_Item,如下图所示:
我们在看main方法生成的il中间码如下所示:
1 .method private hidebysig static void Main(string[] args) cil managed 2 { 3 .entrypoint 4 // Code size 117 (0x75) 5 .maxstack 4 6 .locals init ([0] class Test1.Row r, 7 [1] int32 i, 8 [2] bool CS$4$0000, 9 [3] object[] CS$0$0001) 10 IL_0000: nop 11 IL_0001: ldc.i4.s 10 12 IL_0003: newobj instance void Test1.Row::.ctor(int32) 13 IL_0008: stloc.0 14 IL_0009: ldc.i4.0 15 IL_000a: stloc.1 16 IL_000b: br.s IL_0022 17 IL_000d: nop 18 IL_000e: ldloc.0 19 IL_000f: ldloc.1 20 IL_0010: ldloca.s i 21 IL_0012: call instance string [mscorlib]System.Int32::ToString() 22 IL_0017: callvirt instance void Test1.Row::set_Item(int32, 23 string) 24 IL_001c: nop 25 IL_001d: nop 26 IL_001e: ldloc.1 27 IL_001f: ldc.i4.1 28 IL_0020: add 29 IL_0021: stloc.1 30 IL_0022: ldloc.1 31 IL_0023: ldc.i4.s 10 32 IL_0025: clt 33 IL_0027: stloc.2 34 IL_0028: ldloc.2 35 IL_0029: brtrue.s IL_000d 36 IL_002b: ldc.i4.0 37 IL_002c: stloc.1 38 IL_002d: br.s IL_006b 39 IL_002f: nop 40 IL_0030: ldc.i4.4 41 IL_0031: newarr [mscorlib]System.Object 42 IL_0036: stloc.3 43 IL_0037: ldloc.3 44 IL_0038: ldc.i4.0 45 IL_0039: ldstr "row[" 46 IL_003e: stelem.ref 47 IL_003f: ldloc.3 48 IL_0040: ldc.i4.1 49 IL_0041: ldloc.1 50 IL_0042: box [mscorlib]System.Int32 51 IL_0047: stelem.ref 52 IL_0048: ldloc.3 53 IL_0049: ldc.i4.2 54 IL_004a: ldstr "]=" 55 IL_004f: stelem.ref 56 IL_0050: ldloc.3 57 IL_0051: ldc.i4.3 58 IL_0052: ldloc.0 59 IL_0053: ldloc.1 60 IL_0054: callvirt instance string Test1.Row::get_Item(int32) 61 IL_0059: stelem.ref 62 IL_005a: ldloc.3 63 IL_005b: call string [mscorlib]System.String::Concat(object[]) 64 IL_0060: call void [mscorlib]System.Console::WriteLine(string) 65 IL_0065: nop 66 IL_0066: nop 67 IL_0067: ldloc.1 68 IL_0068: ldc.i4.1 69 IL_0069: add 70 IL_006a: stloc.1 71 IL_006b: ldloc.1 72 IL_006c: ldc.i4.s 10 73 IL_006e: clt 74 IL_0070: stloc.2 75 IL_0071: ldloc.2 76 IL_0072: brtrue.s IL_002f 77 IL_0074: ret 78 } // end of method Program::Main
可以看到代码的22行和60行分别对应的是源码中的为row[i]赋值和取值的语句。我们不难猜测在set_Item和get_Item的代码内部是对Row内部的字符串数组_column进行操作。
从中我们可以总结出,索引器的背后原理实际是调用了对象的set方法和get方法,这就是索引器为我们带来的便利性,简化了我们变成的方式。