C# 列表与列表之间的区别是什么<;T>;和数组索引器?
在reza发完帖子后,我脑海中出现了这个问题C# 列表与列表之间的区别是什么<;T>;和数组索引器?,c#,arrays,generics,struct,C#,Arrays,Generics,Struct,在reza发完帖子后,我脑海中出现了这个问题 >请考虑下面的结构>代码>代码>接口(当然不太有用,但只是显示问题): MyStruct实现了IChangeStruct,因此我们可以直接在堆中更改它的装箱副本,而无需取消装箱并替换为新副本。这可以用以下代码演示: MyStruct[] l1 = new MyStruct[] { new MyStruct(0) }; Console.WriteLine(l1[0].Value); //0 l1[0].Change(10); Console
>请考虑下面的<代码>结构>代码>代码>接口<代码>(当然不太有用,但只是显示问题):
MyStruct
实现了IChangeStruct
,因此我们可以直接在堆中更改它的装箱副本,而无需取消装箱并替换为新副本。这可以用以下代码演示:
MyStruct[] l1 = new MyStruct[]
{
new MyStruct(0)
};
Console.WriteLine(l1[0].Value); //0
l1[0].Change(10);
Console.WriteLine(l1[0].Value); //10
现在,让我们将数组更改为列表
,即:
List<MyStruct> l2 = new List<MyStruct>
{
new MyStruct(0)
};
Console.WriteLine(l2[0].Value); //0
l2[0].Change(10);
Console.WriteLine(l2[0].Value); //also 0
2) 对于列表
:
IL\u 007c:callvirt实例!0类[mscorlib]System.Collections.Generic.List`1::get_项(int32)
IL_0081:stloc.s CS$0$0001
IL_0083:ldloca.s CS$0$0001
IL_0085:ldc.i4.s 10
IL_0087:调用实例void Utils.MyStruct::Change(int32)
但我似乎还没有准备好解释它
那么,列表
返回了什么?或者数组和如何按索引列出返回元素?或者这只是值类型的情况,与引用类型无关
注意:我知道一个人不能改变一个值类型实例,但是所描述的问题让我明白,我从来没有意识到列表和数组是如何工作的。.Net可以使用ldelema
指令(数组元素的加载地址)对数组元素进行适当的寻址
这允许您直接对数组元素进行操作,而无需复制它们。(这也是为什么可以将数组元素作为ref
或out
参数传递的原因)
列表
没有此类功能。相反,list[i]
只是list.get\u Item(i)
的语法糖,这是一个返回结构副本的普通方法调用。数组的索引器以类似于将元素作为ref
参数传递的方式将元素提供给以下代码。任何.net语言中都不存在任何其他类型的行为类似的机制。允许索引访问的任何其他类型都必须公开一对方法,其中一个方法使内部存储的数据的副本可供调用方代码使用,而其中一个方法将以某种方式存储调用方代码中的某些数据的副本。这种限制在值类型中最为明显,但在某些情况下,引用类型也可能有问题(例如,可以在T[]
中的元素上执行联锁.ComapreExchange
,但在具有列表的元素上不执行)
如果要设计自己的集合类型,可以通过提供ActionItem
成员来减轻对索引器的限制,从而允许类似于MyFancyList.ActionItem(4,(ref Point it)=>{it.X+=4;})的代码代码>。提供一系列具有不同数量的额外ref
参数的通用版本可能会有所帮助,这些参数将从调用者处传递(例如MyFancyList.ActOnItem(4)(ref MyThing It,ref Thing newValue,ref Thing compareValue)=>Threading.interlocated.compareeexchange(ref It,newValue,compareValue);
)因为使用这些方法可以避免lambda使用捕获的变量。数组只有在0索引和一维情况下才具有此功能,尽管正确?(因为ldelema
只能在这些限制下工作)
List<MyStruct> l2 = new List<MyStruct>
{
new MyStruct(0)
};
Console.WriteLine(l2[0].Value); //0
l2[0].Change(10);
Console.WriteLine(l2[0].Value); //also 0
IL_0030: ldelema Utils.MyStruct
IL_0035: ldc.i4.s 10
IL_0037: call instance void Utils.MyStruct::Change(int32)
IL_007c: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<valuetype Utils.MyStruct>::get_Item(int32)
IL_0081: stloc.s CS$0$0001
IL_0083: ldloca.s CS$0$0001
IL_0085: ldc.i4.s 10
IL_0087: call instance void Utils.MyStruct::Change(int32)