难以比较两者,它们几乎没有共同之处.C++从C语言继承了这个数组语法和行为.其设计只考虑了一个目标,只考虑了尽可能快.你使用的"分配"这个词已经与运行时发生的不匹配,int [3]语法只是保留了空间.确切地说,发生的位置取决于声明的位置,在函数内部,它将在堆栈帧上保留空间,在外部它将在数据部分中保留空间.
没有执行保证,元素没有初始化,运行时没有跟踪数组的大小,没有索引检查.尽可能快地发布数十亿个错误和数万个恶意软件攻击的功能.缓冲区溢出是在C或C++程序的标准问题,产生非常硬,当它损坏了存储器,随机覆盖其他变量或函数的返回地址来诊断错误.或者简单地使用数据(恶意软件攻击向量)来编写程序.
当然不是C#方式.数组类型是.NET Framework中的引用类型,它们的存储始终从GC堆分配.如果数组很小(小于85KB),快生成#0堆,否则来自大对象堆.抖动和CLR中有很多很多胶水可以使它们尽可能快地完成,尽管它们有以下保证:
有专门的IL操作码来创建一个数组,Opcodes.NewArr,抖动将它转换为直接调用CLR.
这个辅助函数动态地创建数组类型,如果它不存在,但(比较Type.MakeArrayType() ),分配从GC堆的存储和初始化对象,设置长度属性和初始化阵列成员,以便它们全部他们的默认(T)值.
再次访问代码中的数组元素会产生专用的IL操作码,如Opcodes.LdElem.抖动将它们转换为机器代码指令,用于检查数组边界并访问数组元素.
其他数组成员生成对内部SZArrayHelper类的直接调用,并对其进行优化,以便为一维数组生成尽可能快的代码.
抖动中的代码优化器寻找消除数组绑定检查的机会,可以从代码中看到索引表达式不能超出范围.这通常是可能的,特别是当您使用foreach或编写使用数组的Length属性的for(;;)循环时,数组访问的速度与C中的等效数一样快.
垃圾收集器具有内置的数组知识,它在压缩堆时重新排列引用类型的数组元素,因此可以在迭代数组的代码中顺序访问它们.在依赖CPU缓存来快速访问内存的现代处理器上非常非常重要.这是托管代码可以轻松击败本机C或C++代码的地方,本机内存分配在它们碰巧存在的任何地方都会被卡住.
C#仍然具有模拟C数组的语法,没有安全保证.当您发现阵列代码位于程序的关键路径中时,可以使用它们.这些构造要求您使用unsafe关键字,它们与等效的C代码具有相同的问题:
所述stackalloc关键字是可用于分配从堆栈帧代替GC堆的阵列.就像C程序中的本地数组变量一样.当C#代码中的本地数组产生过多垃圾并且GC集合开始占据程序执行时间时,这是一个后备.
该固定关键字可用来声明可以在没有边界检查被访问阵列.stackalloc的替代方案,用于需要在方法调用中存活的数组.当你无法消除索引检查并且分析器告诉你它变得至关重要时,这是一个后备.这通常只适用于短阵列,即元素访问不是主要成本的类型.
在考虑上述信息的情况下解决您的问题:
哪个类是arr的对象?
从第2个子弹中可以看出,数组具有专用类型,并且无需在程序中明确声明它即可动态创建.CLR否则保持这种与元素类型强相关的类型的错觉,就像C#语言语法一样,int数组的数组类型的名称是"System.Int32 []".然而,它是CLR中的一个独特类型,一个逻辑上派生自System.Array的类,实际上派生自System.SZArrayHelper.对于这种类型的诡计,我最喜欢的一句话是"庸医就像打鸭子".
为什么c#的设计者会使用上面的语法?
它是语法糖,非常有效,简短易懂.如果在.NET 1.0中可以使用泛型,它可能看起来有所不同,我有点怀疑它.值得注意的是,C#对于多维数组(例如int[,]
)有太多的糖,而对于锯齿状数组(例如int[][]
)则不够,他们可能会让程序员陷入编写性能不佳的代码.它们很昂贵,索引表达式需要多次乘法和绑定检查,并且以对CPU高速缓存非常不友好的顺序访问数组元素太容易了.
难以比较两者,它们几乎没有共同之处.C++从C语言继承了这个数组语法和行为.其设计只考虑了一个目标,只考虑了尽可能快.你使用的"分配"这个词已经与运行时发生的不匹配,int [3]语法只是保留了空间.确切地说,发生的位置取决于声明的位置,在函数内部,它将在堆栈帧上保留空间,在外部它将在数据部分中保留空间.
没有执行保证,元素没有初始化,运行时没有跟踪数组的大小,没有索引检查.尽可能快地发布数十亿个错误和数万个恶意软件攻击的功能.缓冲区溢出是在C或C++程序的标准问题,产生非常硬,当它损坏了存储器,随机覆盖其他变量或函数的返回地址来诊断错误.或者简单地使用数据(恶意软件攻击向量)来编写程序.
当然不是C#方式.数组类型是.NET Framework中的引用类型,它们的存储始终从GC堆分配.如果数组很小(小于85KB),快生成#0堆,否则来自大对象堆.抖动和CLR中有很多很多胶水可以使它们尽可能快地完成,尽管它们有以下保证:
有专门的IL操作码来创建一个数组,Opcodes.NewArr,抖动将它转换为直接调用CLR.
这个辅助函数动态地创建数组类型,如果它不存在,但(比较Type.MakeArrayType() ),分配从GC堆的存储和初始化对象,设置长度属性和初始化阵列成员,以便它们全部他们的默认(T)值.
再次访问代码中的数组元素会产生专用的IL操作码,如Opcodes.LdElem.抖动将它们转换为机器代码指令,用于检查数组边界并访问数组元素.
其他数组成员生成对内部SZArrayHelper类的直接调用,并对其进行优化,以便为一维数组生成尽可能快的代码.
抖动中的代码优化器寻找消除数组绑定检查的机会,可以从代码中看到索引表达式不能超出范围.这通常是可能的,特别是当您使用foreach或编写使用数组的Length属性的for(;;)循环时,数组访问的速度与C中的等效数一样快.
垃圾收集器具有内置的数组知识,它在压缩堆时重新排列引用类型的数组元素,因此可以在迭代数组的代码中顺序访问它们.在依赖CPU缓存来快速访问内存的现代处理器上非常非常重要.这是托管代码可以轻松击败本机C或C++代码的地方,本机内存分配在它们碰巧存在的任何地方都会被卡住.
C#仍然具有模拟C数组的语法,没有安全保证.当您发现阵列代码位于程序的关键路径中时,可以使用它们.这些构造要求您使用unsafe关键字,它们与等效的C代码具有相同的问题:
所述stackalloc关键字是可用于分配从堆栈帧代替GC堆的阵列.就像C程序中的本地数组变量一样.当C#代码中的本地数组产生过多垃圾并且GC集合开始占据程序执行时间时,这是一个后备.
该固定关键字可用来声明可以在没有边界检查被访问阵列.stackalloc的替代方案,用于需要在方法调用中存活的数组.当你无法消除索引检查并且分析器告诉你它变得至关重要时,这是一个后备.这通常只适用于短阵列,即元素访问不是主要成本的类型.
在考虑上述信息的情况下解决您的问题:
哪个类是arr的对象?
从第2个子弹中可以看出,数组具有专用类型,并且无需在程序中明确声明它即可动态创建.CLR否则保持这种与元素类型强相关的类型的错觉,就像C#语言语法一样,int数组的数组类型的名称是"System.Int32 []".然而,它是CLR中的一个独特类型,一个逻辑上派生自System.Array的类,实际上派生自System.SZArrayHelper.对于这种类型的诡计,我最喜欢的一句话是"庸医就像打鸭子".
为什么c#的设计者会使用上面的语法?
它是语法糖,非常有效,简短易懂.如果在.NET 1.0中可以使用泛型,它可能看起来有所不同,我有点怀疑它.值得注意的是,C#对于多维数组(例如int[,]
)有太多的糖,而对于锯齿状数组(例如int[][]
)则不够,他们可能会让程序员陷入编写性能不佳的代码.它们很昂贵,索引表达式需要多次乘法和绑定检查,并且以对CPU高速缓存非常不友好的顺序访问数组元素太容易了.
c#中的每个变量都是struct或class或enum
C#中的每个变量都有一个类型,该类型是值类型或引用类型.在某些情况下,所有值类型都被分类为struct
,并且所有引用类型都被分类为class
,但这并不常见.如果这就是你的意思,那么"或枚举"是多余的,因为它们是值类型.如果这不是您的意思,有些情况下您会忽略,例如界面类型.
哪个类是arr的对象?
arr
是一个类型的对象int[]
.int[]
是一个派生自的引用类型System.Array
,但除非您调用所有引用类型类类型,否则将它称为类类型.
为什么c#的设计者会使用上面的语法,为什么他们不使用简单的ClassName ObjectName = new ClassName()和数组
"ClassName"是int[]
,因此您的提案将导致int[] arr = new int[](3);
.对于从其他语言进入C#的人来说,这看起来更加冗长,并不熟悉,并且实际上并没有设法简化语言:语言仍需要针对何处[
和]
可能使用的特殊规则.