Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么';这就是C语言中数组的魔力#_C#_Arrays_Clr_Runtime - Fatal编程技术网

C# 什么';这就是C语言中数组的魔力#

C# 什么';这就是C语言中数组的魔力#,c#,arrays,clr,runtime,C#,Arrays,Clr,Runtime,a和b的类型都继承自抽象的System.Array,但是内置库中没有真正的类(似乎有一些运行时类型,您无法找到int[]的类型定义类)。你能告诉我编译时会发生什么吗?他们(c#团队)为什么要进行这种设计(我的意思是为什么它不是像数组,而是使用一个带有编译器魔法的抽象类)?看看这个类 当使用[]语法声明数组时,后台编译器将为您使用此类 对于C#,[]成为继承自System.Array的类型 根据C#4.0规范: §12.1.1系统阵列类型 类型System.Array是所有数组类型的抽象基类型。从

a
b
的类型都继承自抽象的
System.Array
,但是内置库中没有真正的类(似乎有一些运行时类型,您无法找到
int[]
的类型定义类)。你能告诉我编译时会发生什么吗?他们(c#团队)为什么要进行这种设计(我的意思是为什么它不是像
数组
,而是使用一个带有编译器魔法的抽象类)?

看看这个类

当使用
[]
语法声明数组时,后台编译器将为您使用此类

对于C#,
[]
成为继承自
System.Array
的类型

根据C#4.0规范:

§12.1.1系统阵列类型

类型System.Array是所有数组类型的抽象基类型。从任何数组类型到System.array都存在隐式引用转换(§6.1.6),从System.array到任何数组类型都存在显式引用转换(§6.2.4)。请注意,System.Array本身不是数组类型。相反,它是派生所有数组类型的类类型


有这样的阶级。您不能继承它,但当您编写“int[]”时,编译器将创建一个继承System.Array的类型。因此,如果您声明一个变量:

int[] a = new int[5];
string[] b = new string[1];
int[] ints = ...
此变量将具有继承System.Array的类型,因此具有其所有方法和属性

这也类似于学员。定义委托时:

int[] x;

然后类型
Foo
实际上是继承
System的类。MulticastDelegate
Bar
是继承
System的类。Delegate

数组是CLR特有的。它们通过“newarr”指令分配,元素通过“ldelem*”和“stelem*”指令访问,而不是通过System.Array方法

您可以查看ildasm输出以了解数组是如何表示的


因此,为了回答您的问题-不会为任何特定阵列生成新的类型声明。

如果您想了解底层细节,我建议您获取ECMA 335规范并查找阵列:

他们(c#团队)为什么会成功 这个设计(我的意思是为什么它不是 类似数组的东西

泛型是定义容器的理想选择,因为它们约束元素类型,因此您不能插入类型a并尝试检索类型B

但是直到CLR2/C#2才添加泛型。因此数组必须以自己的方式提供类型安全性

即便如此,它与泛型也没有什么不同。您注意到,
int[]
没有特殊的类。但是
Array
也不会有特殊的类。在泛型中,只有泛型类
Array
,CLR“神奇地”为您使用的不同类型参数创建专门的版本。因此,它同样具有“魔力”如果使用泛型

尽管如此,在CLR中,任何对象的类型都是具体化的(它作为一个可以操作的值存在),类型是
type
,并且可以通过
typeof
获得。因此,尽管没有任何数组类型的代码声明(为什么需要查看它?),但是有一个
type
对象可以查询

顺便说一下,数组约束元素类型的方式存在设计缺陷。您可以声明数组:

delegate void Foo(int x);
delegate int Bar(double x);
然后,您可以将其存储在更宽松的变量中:

int[] a = new int[5];
string[] b = new string[1];
int[] ints = ...
但这意味着您可以插入一个字符串(至少在编译时是这样):

在运行时,它会引发异常。静态类型检查的思想是在编译时而不是运行时捕获此类内容。泛型不会有此问题,因为它们不会根据其类型参数的兼容性为泛型类实例提供赋值兼容性。(因为C#4/CLR4,他们已经获得了在有意义的地方这样做的能力,但对于可变数组来说没有意义。)

[]是一种用于在C#中定义数组的语法(语法糖)。可能CreateInstance将在运行时被替换

objs[3] = "Oh dear";

 Array a = Array.CreateInstance(typeof(int), 5); 
CreateInstance的源(取自reflector)

公共静态不安全数组CreateInstance(类型elementType,int-length)
{
if(elementType==null)
{
抛出新ArgumentNullException(“elementType”);
}
RuntimeType underlyingSystemType=elementType.underlyingSystemType作为RuntimeType;
if(underlyngSystemType==null)
{
抛出新的ArgumentException(Environment.GetResourceString(“Arg_MustBeType”),“elementType”);
}
如果(长度<0)
{
抛出新ArgumentOutOfRangeException(“长度”,Environment.GetResourceString(“ArgumentOutOfRange_NeedNonNegnNum”);
}
返回InternalCreate((void*)underlyingSystemType.TypeHandle.Value,1,&长度,null);
}

试图在.NET类型的系统中对此进行解释并不会让您走多远。JIT编译器和CLR中内置了核心支持,用于处理创建数组的问题。类似这样的语句:

public static unsafe Array CreateInstance(Type elementType, int length)
{
    if (elementType == null)
    {
        throw new ArgumentNullException("elementType");
    }
    RuntimeType underlyingSystemType = elementType.UnderlyingSystemType as RuntimeType;
    if (underlyingSystemType == null)
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeType"), "elementType");
    }
    if (length < 0)
    {
        throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    return InternalCreate((void*) underlyingSystemType.TypeHandle.Value, 1, &length, null);
}
生成此IL:

        var arr = new int[5];
JIT编译器随后将其转换为以下机器代码:

  IL_0001:  ldc.i4.5
  IL_0002:  newarr     [mscorlib]System.Int32
这里的核心成分是专用的IL操作码newarr,而不是通常创建类实例的newobj操作码。以及到实际创建对象的CLR帮助函数的简单转换。您也可以使用SSCLI20源代码查看此帮助函数,
CLR\src\vm\jithelpers.cpp
这里要发布的代码非常大,但它经过了大量优化,以使此类代码尽可能快地运行,可以直接访问CLR代码可用的类型内部


其中有两个可用的帮助程序,JIT_NewArr1()创建一维(向量)数组,JIT_NewMDArr()创建多维数组。与Type.MakeArrayType()可用的两个重载相比。

我仔细阅读了,所以我想我应该分享我读到的内容

精确的数组类型由VE自动创建
00000035  mov         edx,5                 ; arg2 = array size
0000003a  mov         ecx,6F535F06h         ; arg1 = typeof(int)
0000003f  call        FFD52128              ; call JIT_NewArr1(type, size)