rud*_*ter 6 c# arrays .net-3.5 implicit-conversion
我在.Net 3.5,Visual Studio 2012中编译了以下代码.
当数组被分配给我的IReadOnlyCollection时,我期望在该行上出现错误,因为没有从Array定义到我的接口的隐式转换.它编译成功,也不会创建任何运行时错误.
需要注意的注意事项:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是IL代码的方式:
.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
}
Run Code Online (Sandbox Code Playgroud)
我所说的只是纯粹的猜测,但它不适合作为评论,所以我无论如何都会将其发布为答案:
所以区别实际上是编译器版本。
由于类的名称和命名空间很重要,我假设它是 VS 2012+ 编译器中引入的硬编码规则,以支持 .Net 4.5 引入的新类型/接口的隐式转换。
所以我猜这是数组的另一个黑魔法。例如,参见Hans Passant 的回答:
编译器和 CLR 都对数组类型有特殊的了解,就像它们对值类型的了解一样。编译器看到您尝试转换为 IList<> 并说“好吧,我知道该怎么做!”。