1

Well I know that Array in C# is an object but a bit of code has confused me actually

int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0};
foreach (int i in numbers)      
        Console.WriteLine(i);

to access an arbitrary property of an arbitrary object int value= object.property;

in this loop it's kind of accessing the properties, but how ? and what is the property itself here ? how they are being organized?

Worthy Null
  • 33
  • 1
  • 8
  • 5
    Your question is a little unclear; can you try to restate it? There doesn't seem to be much of a connection between the title of the question and the two code snippets you provide. For instance, how does `int value = object.property` relate to the question or the larger code snippet? Is your question about the internals and implementation details of an array in C#, or are you curious about the `foreach` loop language construct? – Dan Forbes Mar 21 '16 at 14:06
  • 2
    Do you have a JavaScript background? – usr Mar 21 '16 at 14:07
  • 5
    This does not access any properties, but just iterates over an `IEnumerable` (an interface which arrays implement) and accesses each element in this process using the foreach loop [MSDN][https://msdn.microsoft.com/de-at/library/ttw7t8t6.aspx] – derpirscher Mar 21 '16 at 14:09
  • 1
    I think you're confused as to what a property is. The numbers in your array are not properties. A property would be the array length for example. What the foreach is doing in the case of an array is creating a for loop under the hood. If it wasn't an array, and was instead a list or dictionary it would create a hashset and implement GetEnumerator() and use MoveNext() and Current() to be able to enumerate the collection. – sr28 Mar 21 '16 at 14:43
  • 1
    @derpirscher Actually that's not true. `foreach` for arrays (and strings) is compiled as a true for loop and doesn't touch the enumerator in `IEnumerable`. It might check for its existence when validating, but I even doubt that. Here, you can look for yourself what happens: https://dotnetfiddle.net/c6UcQP ; view IL -- there's no enumerator there. Still, on a high level you are correct as to what it does. – atlaste Mar 21 '16 at 14:43
  • @atlaste You're right, didn't know that. – derpirscher Mar 21 '16 at 14:49

2 Answers2

3

How data is stored

Basically an array is a blob of data. Integers are value types of 32-bit signed integers.

Identifiers in C# are either pointers to objects, or the actual values. In the case of reference types, they are real pointers, in the case of values types (e.g. int, float, etc) they are the actual data. int is a value type, int[] (array to integers) is a reference type.

The reason it works like this is basically "efficiency": the overhead of copying 4 bytes or 8 bytes for a value type is very small, while the overhead of copying an entire array can be quite extensive.

If you have an array containing a N integers, it's nothing more than a blob of N*4 bytes, with the variable pointing to the first element. There is no name for each element in the blob.

E.g.:

int[] foo = new int[10]; // allocates 40 bytes, naming the whole thing 'foo'
int f = foo[2]; // allocates variable 'f', copies the value of 'foo[2]' into 'f'.

Access the data

As for foreach... In C#, all collections implement an interface named IEnumerable<T>. If you use it, the compiler will in this case notice that it's an integer array and it will loop through all elements. In other words:

foreach (int f in foo) // copy value foo[0] into f, then foo[1] into f, etc
{ 
    // code
}

is (in the case of arrays!) the exact same thing as:

for (int i=0; i<foo.Length; ++i)
{
    int f = foo[i];
    // code
}

Note that I explicitly put "in the case of arrays" here. Arrays are an exceptional case for the C# compiler. If you're not working with arrays (but f.ex. with a List, a Dictionary or something more complex), it works a bit differently, namely by using the Enumerator and IDisposable. Note that this is just a compiler optimization, arrays are perfectly capable of handling IEnumerable.

For those interested, basically it'll generate this for non-arrays and non-strings:

var e = myEnumerable.GetEnumerator();
try
{
    while (e.MoveNext())
    {
        var f = e.Current;
        // code
    }
}
finally
{
    IDisposable d = e as IDisposable;
    if (d != null)
    {
        d.Dispose();
    }
}

If you want a name

You probably need a Dictionary.

atlaste
  • 30,418
  • 3
  • 57
  • 87
  • Yes, as you say, plain arrays X[] are handled specially by the compiler for `foreach`. (And we know this because `foreach` exists in .Net 1.x, but `IEnumerable` does NOT exist in .Net 1.x.) – Matthew Watson Mar 21 '16 at 14:24
  • @MatthewWatson Well, yes and no. Yes: in the old style, foreach used to cast for certain cases. `foreach (string s in myOldCollection)` where the values were casted to strings. However, it also has to do with the IL opcodes and a trivial optimization that the compiler can make (for both `string`s and arrays) using the `ldlen` opcode - in which case it also doesn't need to check `IDisposable`. – atlaste Mar 21 '16 at 14:33
  • How arrays implement `IEnumerable` and friends is actually quite interesting - there's a lot of runtime hacking to it. But as far as your code is concerned, `T[]` implements `IEnumerable`, even though the array type itself is neither generic nor does it "really" implement the interface. Smoke and mirrors :) – Luaan Mar 21 '16 at 14:44
  • 1
    A big difference between `foreach` for arrays compared to for `IEnumerable` is that IL code generated for the latter will make calls to `IEnumerator.GetEnumerator()` and `IEnumerator.MoveNext()`, whereas the former does not make any such calls (and is thus much faster). – Matthew Watson Mar 21 '16 at 14:46
  • 1
    Example of IL decompiled code foreach for arrays vs arrays: http://goo.gl/H1IsFr . The `Print1()` and `Print2()` generate **exactly** the same IL code. – xanatos Mar 21 '16 at 14:55
  • @Luaan Yes I know. And according to spec it checks for `IEnumerable`. What I meant to say is that when I last read the IL emitting code in the compiler, I noticed that the compiler simply checks if the variable is an array - and if that's the case, emit code like this. In reality there's no `IEnumerable` involved here -- except that we all know how array and IEnumerable... oh well you get my point. PS just noticed that xanatos posted exactly what I mean in IL. – atlaste Mar 21 '16 at 14:57
  • 1
    As a sidenote, the `foreach` **for non-array types** cheats and uses duck typing as the primary source of the enumerable, not `IEnumerable`/`IEnumerable`. See for example http://stackoverflow.com/a/20311361/613130 – xanatos Mar 21 '16 at 14:58
0

An array is just a collection, or IEnumerable<T> where T represents a particular type; in your case int (System.Int32)

Memory allocation...

An int is 32 bits long, and you want an array of 10 items

int[] numbers = new int[10];

32 x 10 = 320 bits of memory allocated

Memory access...

Say your array starts at 0000:0000 and you want to access index n [0-9] of the array...

Pseudo code...

index = n
addressof(n) = 0000:0000 + (sizeof(int) * index)

or

index = 2
addressof(n) = 0000:0000 + (32 * 2)

This is a simplified example of what happens when you access each indexed item within the array (your foreach loop sort of does this)

A foreach loop works by referencing each element in the array (in your case, the reference is called i).

Why you are NOT accessing by property...

In an array, items are stored by index, not by name...

... so you can't...

numbers.1
numbers.2

...but you can...

numbers[1]
numbers[2]

Since every object derives from object, you can access arbitrary members of the particular type...

numbers[1].GetHashCode();

Example:

//Define an array if integers, shorthand (see, memory allocation)...
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

//For each element in the array (under the hood, get the element's address in memory and hold this in a reference called i)...
foreach(int i in numbers)
{
    // Call GetHashCode() on the instance pointed to by i and pass the reference (by value) to the Console.WriteLine method.
    Console.WriteLine(i.GetHashCode());
}
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
  • I'm genuinely curious what the OP's question is. When you say they "would be right", what do you mean? – Dan Forbes Mar 21 '16 at 14:24
  • The OP was simply wondering how you could get to the actual values of the array without directly accessing a property. He simply didn' understand the IEnumerable and the "in" functionality of c#. – DiscipleMichael Mar 21 '16 at 14:37