Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 列表与列表之间的区别是什么<;T>;和数组索引器?_C#_Arrays_Generics_Struct - Fatal编程技术网

C# 列表与列表之间的区别是什么<;T>;和数组索引器?

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

在reza发完帖子后,我脑海中出现了这个问题

>请考虑下面的<代码>结构>代码>代码>接口<代码>(当然不太有用,但只是显示问题):

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)