Che*_*hen 22 c# arrays clr runtime
int[] a = new int[5];
string[] b = new string[1];
Run Code Online (Sandbox Code Playgroud)
两者的类型a
和b
继承自抽象System.Array
,但内置库中没有真正的类(似乎有一些运行时类型,你找不到类型定义类的一个int[]
).你能告诉我编译时会发生什么吗?为什么他们(c#团队)制作这个设计(我的意思是为什么它不是这样的Array<T>
,而是他们使用带编译器魔法的抽象类)?
Han*_*ant 18
试图在.NET类型系统中解释这一点并不会让你走得太远.JIT编译器和CLR内置了核心支持来处理创建数组.这样的陈述:
var arr = new int[5];
Run Code Online (Sandbox Code Playgroud)
生成此IL:
IL_0001: ldc.i4.5
IL_0002: newarr [mscorlib]System.Int32
Run Code Online (Sandbox Code Playgroud)
然后JIT编译器将其转换为此机器代码:
00000035 mov edx,5 ; arg2 = array size
0000003a mov ecx,6F535F06h ; arg1 = typeof(int)
0000003f call FFD52128 ; call JIT_NewArr1(type, size)
Run Code Online (Sandbox Code Playgroud)
这里的核心成分是专用的IL操作码newarr,而不是通常的newobj操作码,它创建了一个类的实例.并简单地转换为实际获取创建对象的CLR帮助函数.您可以使用SSCLI20源代码查看此辅助函数clr\src\vm\jithelpers.cpp
.这里发布的内容太大了,但它经过大量优化,可以尽可能快地运行这种代码,可以直接访问CLR代码可用的类型内部.
有两个这样的助手可用,JIT_NewArr1()创建一维(向量)数组,JIT_NewMDArr()创建多维数组.比较Type.MakeArrayType()可用的两个重载.
为什么他们(c#团队)制作这个设计(我的意思是为什么它不像Array那样......
泛型是定义容器的理想选择,因为它们约束元素类型,因此您无法插入类型A并尝试检索类型B.
但是直到CLR2/C#2才添加泛型.因此阵列必须以自己的方式提供类型安全性.
即便如此,它与泛型并没有什么不同.你注意到没有特殊的课程int[]
.但也不会有Array<int>
.在泛型中,只有泛型类Array<T>
,而CLR"神奇地"为您使用的不同类型参数创建专用版本.因此,如果使用仿制药,那将毫不逊色.
尽管如此,在CLR中,任何对象的类型都是有效的(它可以作为一个可以操作的值存在),类型Type
,并且可以获得typeof
.因此,虽然没有任何数组类型的代码声明(为什么你需要看到它?)Type
,你可以查询一个对象.
顺便说一句,数组约束元素类型的方式存在设计缺陷.你可以声明一个数组:
int[] ints = ...
Run Code Online (Sandbox Code Playgroud)
然后,您可以将其存储在一个更宽松的变量中:
object[] objs = ints;
Run Code Online (Sandbox Code Playgroud)
但这意味着您可以插入一个字符串(至少它在编译时出现):
objs[3] = "Oh dear";
Run Code Online (Sandbox Code Playgroud)
在运行时它会抛出异常.静态类型检查的想法是在编译时捕获这种东西,而不是运行时.泛型不会遇到此问题,因为它们不会根据类型参数的兼容性为泛型类实例赋予赋值兼容性.(自从C#4/CLR4以来,他们已经获得了在有意义的地方做到这一点的能力,但这对于可变数组来说是没有意义的.)