4

I know that List<T> indexers, for example, resemble properties. Taken from msdn:

Indexers allow instances of a class or struct to be indexed just like arrays. Indexers resemble properties except that their accessors take parameters.

But I can't understand why the following happens:

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

Aren't they supposed to work in the same way?

Arthur Castro
  • 610
  • 6
  • 18

2 Answers2

7

The indexer for List<T> allows you to access the elements using properties (Methods) which makes it look like an array. You can't pass the generated method by ref as if you wrote :

Interlocked.Increment(ref myList.GetItem.get_Item(0));

But accessing array's elements is not though an indexer. Accessing array elements is directly supported in the CLR. So array[i] returns a variable that can be passed by ref.

From C# Specs:

Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable. Thus, it is not possible to pass an indexer element as a ref or out argument.

This is the indexer of List<T> (which internally uses an array):

public T this[int index]
{
    get
    { // some checks removed 
        return _items[index];
    }

    set { _items[index] = value;}
}

From IL Side:

Accessing an array element generates this direct IL instruction:

IL_0014: ldelem.i4

Accessing a List's element through indexer generates this:

IL_001b:  callvirt   instance !0 class [mscorlib]System.Collections.Generic.List`1<int32>::get_Item(int32)

So, it is the same c# syntax. But the generated IL is completely different.

Zein Makki
  • 29,485
  • 6
  • 52
  • 63
  • "Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable.". Exactly what I wanted to read: The index from arrays return the variable itself. – Arthur Castro Jul 01 '16 at 16:21
4

It's because indexers are properties and properties are ultimately functions. Because they are functions, they don't (necessarily) refer to a specific location in memory like an array index does. If the language DID allow it, developers would be able to easily break the reference and out semantics and it just wouldn't work right. Case in point:

public class Foo {
        public int this[int x] {
            get {
                return 1;
            }
            set {
                //meh. whatever. 
            }
        }
    }

If I pass Foo[0] as an out parameter, what just happened? In this case, I don't even set anything. This completely breaks the semantics of ref and out.

aquinas
  • 23,318
  • 5
  • 58
  • 81
  • Beat me to it, though I would have just referenced line 174 here...http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs – Matthew Layton Jul 01 '16 at 14:49
  • 'indexers are properties and properties are ultimately functions'. Using this same logic, array indexes are properties and ultimately functions too, but they act differently, as you can see in the example in the question. – Arthur Castro Jul 01 '16 at 16:11
  • No, indexes and indexers are two different things. – aquinas Jul 01 '16 at 16:20