Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are Array Indexes?

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?

like image 848
Arthur Castro Avatar asked Dec 19 '22 15:12

Arthur Castro


2 Answers

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.

like image 167
Zein Makki Avatar answered Dec 21 '22 04:12

Zein Makki


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.

like image 24
aquinas Avatar answered Dec 21 '22 05:12

aquinas