foreach with generics and without generics

T

Tony Johansson

Hello!

The first block of code below is just using an ArrayList. The ArrayList is
implementing IEnumerable that look like this.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}

IEnumerator look like this
public interface IEnumerator
{
bool MoveNext();
void Reset();
object Current { get; }
}

Now to my question as you can see property Current is returning an object
but in the foreach below I don't have to use
any kind of cast. Can somebody explain that ?

In the second block of code example I use generics which mean I use
IEnumerable<T> but as you can see the code is identical to the code when non
generics was used
Normally the code you write is different when you use generics compared to
when no generics is used.
For example if you compare between implementing IComparable and
IComparable<T> we have different
signature in method CompareTo

So can somebody give an example of a piece of code that a need for a cast is
required becuse of propery Current is returning
an object.

first block of code
*************
{
ArrayList list = new ArrayList();
list.Add(4);
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(9);
foreach (int number in list)
Console.WriteLine(number);
}
second block of code
****************
{
List<int> myList = new List<int>();
myList.Add(4);
myList.Add(1);
myList.Add(2);
myList.Add(3);
myList.Add(9);
foreach (int number in myList)
Console.WriteLine(number);
}

//Tony
 
P

Peter Duniho

Tony said:
[...]
Now to my question as you can see property Current is returning an object
but in the foreach below I don't have to use
any kind of cast. Can somebody explain that ?

If you look at the IL generated by the compiler, you'll see that the
cast is implicit.
In the second block of code example I use generics which mean I use
IEnumerable<T> but as you can see the code is identical to the code when non
generics was used
Normally the code you write is different when you use generics compared to
when no generics is used.
For example if you compare between implementing IComparable and
IComparable<T> we have different
signature in method CompareTo

So can somebody give an example of a piece of code that a need for a cast is
required becuse of propery Current is returning
an object.

Sure:

IEnumerator enum = list.GetEnumerator();

while (enum.MoveNext())
{
int number = (int)enum.Current;

Console.WriteLine(number);
}

Note the cast when retrieving the value from "enum.Current".

Pete
 
T

Tony Johansson

Hello!

Below this code snipped is the IL code.
Can you just tell me which line in the IL below show that the cast is
implicit.

class Program
{
static void Main(string[] args)
{
ArrayList list = new ArrayList();
list.Add(4);
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(9);
foreach (int number in list)
Console.WriteLine(number);
}
}

method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 250 (0xfa)
.maxstack 2
.locals init ([0] class [mscorlib]System.Collections.ArrayList list,
[1] int32 number,
[2] class [mscorlib]System.Collections.Generic.List`1<int32>
myList,
[3] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
[4] bool CS$4$0001,
[5] class [mscorlib]System.IDisposable CS$0$0002,
[6] valuetype
[mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0003)
IL_0000: nop
IL_0001: newobj instance void
[mscorlib]System.Collections.ArrayList::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.4
IL_0009: box [mscorlib]System.Int32
IL_000e: callvirt instance int32
[mscorlib]System.Collections.ArrayList::Add(object)
IL_0013: pop
IL_0014: ldloc.0
IL_0015: ldc.i4.1
IL_0016: box [mscorlib]System.Int32
IL_001b: callvirt instance int32
[mscorlib]System.Collections.ArrayList::Add(object)
IL_0020: pop
IL_0021: ldloc.0
IL_0022: ldc.i4.2
IL_0023: box [mscorlib]System.Int32
IL_0028: callvirt instance int32
[mscorlib]System.Collections.ArrayList::Add(object)
IL_002d: pop
IL_002e: ldloc.0
IL_002f: ldc.i4.3
IL_0030: box [mscorlib]System.Int32
IL_0035: callvirt instance int32
[mscorlib]System.Collections.ArrayList::Add(object)
IL_003a: pop
IL_003b: ldloc.0
IL_003c: ldc.i4.s 9
IL_003e: box [mscorlib]System.Int32
IL_0043: callvirt instance int32
[mscorlib]System.Collections.ArrayList::Add(object)
IL_0048: pop
IL_0049: nop
IL_004a: ldloc.0
IL_004b: callvirt instance class
[mscorlib]System.Collections.IEnumerator
[mscorlib]System.Collections.ArrayList::GetEnumerator()
IL_0050: stloc.3
.try
{
IL_0051: br.s IL_0066
IL_0053: ldloc.3
IL_0054: callvirt instance object
[mscorlib]System.Collections.IEnumerator::get_Current()
IL_0059: unbox.any [mscorlib]System.Int32
IL_005e: stloc.1
IL_005f: ldloc.1
IL_0060: call void [mscorlib]System.Console::WriteLine(int32)
IL_0065: nop
IL_0066: ldloc.3
IL_0067: callvirt instance bool
[mscorlib]System.Collections.IEnumerator::MoveNext()
IL_006c: stloc.s CS$4$0001
IL_006e: ldloc.s CS$4$0001
IL_0070: brtrue.s IL_0053
IL_0072: leave.s IL_0090
} // end .try
finally
{
IL_0074: ldloc.3
IL_0075: isinst [mscorlib]System.IDisposable
IL_007a: stloc.s CS$0$0002
IL_007c: ldloc.s CS$0$0002
IL_007e: ldnull
IL_007f: ceq
IL_0081: stloc.s CS$4$0001
IL_0083: ldloc.s CS$4$0001
IL_0085: brtrue.s IL_008f
IL_0087: ldloc.s CS$0$0002
IL_0089: callvirt instance void
[mscorlib]System.IDisposable::Dispose()
IL_008e: nop
IL_008f: endfinally
} // end handler
IL_0090: nop
IL_0091: newobj instance void class
[mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0096: stloc.2
IL_0097: ldloc.2
IL_0098: ldc.i4.4
IL_0099: callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_009e: nop
IL_009f: ldloc.2
IL_00a0: ldc.i4.1
IL_00a1: callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_00a6: nop
IL_00a7: ldloc.2
IL_00a8: ldc.i4.2
IL_00a9: callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_00ae: nop
IL_00af: ldloc.2
IL_00b0: ldc.i4.3
IL_00b1: callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_00b6: nop
IL_00b7: ldloc.2
IL_00b8: ldc.i4.s 9
IL_00ba: callvirt instance void class
[mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_00bf: nop
IL_00c0: nop
IL_00c1: ldloc.2
IL_00c2: callvirt instance valuetype
[mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class
[mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_00c7: stloc.s CS$5$0003
.try
{
IL_00c9: br.s IL_00da
IL_00cb: ldloca.s CS$5$0003
IL_00cd: call instance !0 valuetype
[mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_00d2: stloc.1
IL_00d3: ldloc.1
IL_00d4: call void [mscorlib]System.Console::WriteLine(int32)
IL_00d9: nop
IL_00da: ldloca.s CS$5$0003
IL_00dc: call instance bool valuetype
[mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_00e1: stloc.s CS$4$0001
IL_00e3: ldloc.s CS$4$0001
IL_00e5: brtrue.s IL_00cb
IL_00e7: leave.s IL_00f8
} // end .try
finally
{
IL_00e9: ldloca.s CS$5$0003
IL_00eb: constrained. valuetype
[mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
IL_00f1: callvirt instance void
[mscorlib]System.IDisposable::Dispose()
IL_00f6: nop
IL_00f7: endfinally
} // end handler
IL_00f8: nop
IL_00f9: ret
} // end of method Program::Main




Peter Duniho said:
Tony said:
[...]
Now to my question as you can see property Current is returning an object
but in the foreach below I don't have to use
any kind of cast. Can somebody explain that ?

If you look at the IL generated by the compiler, you'll see that the cast
is implicit.
In the second block of code example I use generics which mean I use
IEnumerable<T> but as you can see the code is identical to the code when
non
generics was used
Normally the code you write is different when you use generics compared
to
when no generics is used.
For example if you compare between implementing IComparable and
IComparable<T> we have different
signature in method CompareTo

So can somebody give an example of a piece of code that a need for a cast
is
required becuse of propery Current is returning
an object.

Sure:

IEnumerator enum = list.GetEnumerator();

while (enum.MoveNext())
{
int number = (int)enum.Current;

Console.WriteLine(number);
}

Note the cast when retrieving the value from "enum.Current".

Pete
 
P

Peter Duniho

Tony said:
Hello!

Below this code snipped is the IL code.
Can you just tell me which line in the IL below show that the cast is
implicit.

Sure. It's right here:
[...]
IL_0054: callvirt instance object
[mscorlib]System.Collections.IEnumerator::get_Current()
IL_0059: unbox.any [mscorlib]System.Int32

The unboxing of the object includes a type check and cast to the target
type.

Try it with a non-generic enumerator for a reference type, and you'll
see a more explicit cast. In this case, because you're using a value
type (System.Int32), the cast is in the form of something you might not
immediately recognize as one (i.e. the unboxing).

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top