什么是数组索引?

时间:2016-07-01 14:27:23

标签: c# arrays indexing

我知道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

他们不应该以同样的方式工作吗?

2 个答案:

答案 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 Side:

访问数组元素会生成此直接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参数传递,那刚刚发生了什么?在这种情况下,我甚至没有设置任何。这完全打破了refout的语义。