我知道List<T>
索引器就像属性一样。取自msdn:
索引器允许将类或结构的实例编入索引,就像一样 的阵列即可。索引器类似于属性,除了它们的访问器 参数。
但我无法理解为什么会发生以下情况:
int[] myArray = new int[0];
List<int> myList = new List<int>();
Interlocked.Increment(ref myArray[0]); // fine
Interlocked.Increment(ref myList[0]); //CS0206 A property or indexer may not be passed as an out or ref parameter
他们不应该以同样的方式工作吗?
答案 0 :(得分:7)
List<T>
的索引器允许您使用属性(方法)访问元素,使其看起来像一个数组。您无法通过ref
传递生成的方法,就像您写的那样:
Interlocked.Increment(ref myList.GetItem.get_Item(0));
但访问数组的元素不是索引器。在CLR 中直接支持访问数组元素。因此array[i]
会返回一个可由ref
传递的变量。
来自C#规格:
即使访问索引器元素的语法与 对于数组元素,索引器元素不归类为a 变量。因此,不可能将索引器元素作为ref传递 或者说出论点。
这是List<T>
的索引器(内部使用数组):
public T this[int index]
{
get
{ // some checks removed
return _items[index];
}
set { _items[index] = value;}
}
访问数组元素会生成此直接IL指令:
IL_0014: ldelem.i4
通过索引器访问List的元素会生成:
IL_001b: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)
所以,它是相同的c#语法。但生成的IL完全不同。
答案 1 :(得分:4)
这是因为索引器是属性,属性最终是函数。因为它们是函数,所以它们(必然)不像数组索引那样引用内存中的特定位置。如果语言DID允许它,开发人员将能够轻松地破坏引用和语义,它只是无法正常工作。一个很好的例子:
public class Foo {
public int this[int x] {
get {
return 1;
}
set {
//meh. whatever.
}
}
}
如果我将Foo[0]
作为out参数传递,那刚刚发生了什么?在这种情况下,我甚至没有设置任何。这完全打破了ref
和out
的语义。