如何在列表和数组中定义索引器.
List<MyStruct> lists=new List<MyStruct>();
MyStruct
结构在哪里.现在考虑一下
MyStruct[] arr=new MyStruct[10];
arr[0]
给出了第一个Structure项的引用.但是lists[0]
给了我一份它的副本.是否有任何理由这样做.此外,由于Int32
结构是List<Int32> list1 =new List<Int32>();
如何可以访问list1[0]
或分配list1[0]=5
在不可能的地方lists[0]._x=5
the*_*oop 10
尽管它们看起来相同,但数组索引器和列表索引器正在完全分开.
该List<T>
索引声明为带参数的属性:
public T this[int index] { get; set; }
Run Code Online (Sandbox Code Playgroud)
这会被编译为get_Item
和set_Item
访问参数时像任何其他方法一样被调用的方法.
数组索引器在CLR中有直接支持; 有一个特定的IL指令ldelema
(加载元素地址),用于获取指向数组第n个元素的托管指针.然后,该指针可以被任何其他IL指令使用,这些指令将指针直接改变该地址处的东西.
例如,stfld
(存储字段值)指令可以使用指定"this"实例的托管指针来存储字段,或者您可以使用指针直接在数组中的事物上调用方法.
在C#parlance中,数组索引器返回一个变量,但列表索引器返回一个值.
最后一点:
lists[0]._x=5
Run Code Online (Sandbox Code Playgroud)
实际上只是对你早期观点的重述:
arr[0]
给出了第一个Structure项的引用.但是lists[0]
给了我一份它的副本.
如果您编辑了它的副本,则更改将丢失到以太,即
var throwawayCopy = lists[0];
throwawayCopy._x = 5;
// (and never refer to throwawayCopy again, ever)
Run Code Online (Sandbox Code Playgroud)
因为这几乎肯定不是你想要的,编译器不会让你.然而,可变的结构是邪恶的.这里更好的选择是不要使用可变结构.他们咬了一口.
把它降低到一个水平,到一个简单而具体的例子:
using System;
struct Evil
{
public int Yeuch;
}
public class Program
{
public static void Main()
{
var pain = new Evil[] { new Evil { Yeuch = 2 } };
pain[0].Yeuch = 27;
Console.WriteLine(pain[0].Yeuch);
}
}
Run Code Online (Sandbox Code Playgroud)
这将编译(在这里查看最后两行):
L_0026: ldloc.0 <== pain
L_0027: ldc.i4.0 <== 0
L_0028: ldelema Evil <== get the MANAGED POINTER to the 0th element
(not the 0th element as a value)
L_002d: ldc.i4.s 0x1b <== 27
L_002f: stfld int32 Evil::Yeuch <== store field
L_0034: ldloc.0 <== pain
L_0035: ldc.i4.0 <== 0
L_0036: ldelema Evil <== get the MANAGED POINTER to the 0th element
(not the 0th element as a value)
L_003b: ldfld int32 Evil::Yeuch <== read field
L_0040: call void [mscorlib]System.Console::WriteLine(int32) <== writeline
L_0045: ret
Run Code Online (Sandbox Code Playgroud)
它从来没有真正与结构作为一个值进行对话- 没有副本等
归档时间: |
|
查看次数: |
9806 次 |
最近记录: |