I compiled the following code in .Net 3.5, Visual Studio 2012.
I expected to get an error on the line when the array gets assigned to my IReadOnlyCollection, because there is no implicit conversion defined from Array to my Interface. It compiles successful and does also not create any runtime errors.
Notes to be aware of:
File1.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace System.Collections.Generic
{
public interface IReadOnlyCollection<T> : IEnumerable<T>, IEnumerable
{
int Count
{
get;
}
}
}
File2.cs:
using System.Collections.Generic;
namespace ConsoleApplication1
{
public class Test
{
public Test()
{ }
}
class Program
{
static void Main(string[] args)
{
Test[] foo = { new Test(), new Test(), new Test() };
IReadOnlyCollection<Test> bar = foo;
int count = bar.Count;
}
}
}
This is the IL code by the way:
.method private hidebysig static void Main (
string[] args
) cil managed
{
.entrypoint
.locals init (
[0] class ConsoleApplication1.Test[] foo,
[1] class System.Collections.Generic.IReadOnlyCollection`1<class ConsoleApplication1.Test> bar,
[2] int32 count,
[3] class ConsoleApplication1.Test[] CS$0$0000
)
IL_0000: nop
IL_0001: ldc.i4.3
IL_0002: newarr ConsoleApplication1.Test
IL_0007: stloc.3
IL_0008: ldloc.3
IL_0009: ldc.i4.0
IL_000a: newobj instance void ConsoleApplication1.Test::.ctor()
IL_000f: stelem.ref
IL_0010: ldloc.3
IL_0011: ldc.i4.1
IL_0012: newobj instance void ConsoleApplication1.Test::.ctor()
IL_0017: stelem.ref
IL_0018: ldloc.3
IL_0019: ldc.i4.2
IL_001a: newobj instance void ConsoleApplication1.Test::.ctor()
IL_001f: stelem.ref
IL_0020: ldloc.3
IL_0021: stloc.0
IL_0022: ldloc.0
IL_0023: stloc.1
IL_0024: ldloc.1
IL_0025: callvirt instance int32 class System.Collections.Generic.IReadOnlyCollection`1<class ConsoleApplication1.Test>::get_Count()
IL_002a: stloc.2
IL_002b: ret
}
All I'm saying is pure guess, but it doesn't fit as a comment so I'm posting it as an answer anyway:
So the difference is really the compiler version.
As the name of the class and the namespace are important, I'm assuming it's a hardcoded rule that has been introduced in the compiler of VS 2012+, to support implicit conversion of the new types/interfaces introduced with .Net 4.5.
So I'm guessing it's another black magic trick with arrays. See for example this Hans Passant answer:
Both the compiler and the CLR have special knowledge of array types, just as they do of value types. The compiler sees your attempt at casting to IList<> and says "okay, I know how to do that!".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With