Array.Initialize - 为什么这个方法存在?

时间:2015-11-25 14:59:18

标签: c# .net arrays

我今天偶然发现了一种方法。我在谈论:Array.Initialize()

根据文件:

  

此方法旨在帮助编译器支持值类型数组;大多数用户不需要这种方法。

此方法如何负责使编译器支持值类型?至于我关心这个方法只是:

  

通过调用值类型的默认构造函数来初始化value-type Array的每个元素。

另外,为什么公开?我不认为自己需要调用这个方法,编译器在创建时已经初始化了数组,所以手动调用这个方法将是多余的,没用。

即使我的意图是重置数组的值,我仍然不会调用它,我会创建一个新的。 array = new int[]

所以,似乎这个方法只是为了编译器而存在。为什么是这样?谁能给我更多细节呢?

4 个答案:

答案 0 :(得分:12)

值得注意的是,.NET的规则与C#的规则不同。

我们可以在.NET中做些我们无法在C#中做的事情,通常是因为代码不可验证(例如ref返回类型),或者因为它们可能引入一些混淆。

在C#struct中,不能有一个已定义的无参数构造函数,并且调用new SomeValueType()可以通过创建零填充的内存部分来工作(因此,对于数字类型,所有字段都是0,{ {1}}用于引用类型,并且对于其他值类型再次使用相同规则的结果。)

在.NET中,您可以在值类型上使用无参数构造函数。

这样做可能是一个坏主意。一方面关于它被调用的规则以及当值的内存被填零时的规则,以及在不同情况下分配时发生的事情都不是完全简单的(例如null会调用它但是new SomeValueType()new T()的通用方法中的T不会!)。如果SomeValueType的结果总是零填充,则生活会更简单。毫无疑问,这会影响C#的设计,即使.NET确实如此。

由于这个原因,Array.Initialize()对于用C#编写的任何类型的新数组都没有意义,因为调用构造函数和零填充是一回事。

但是出于同样的原因,一个类型可以用另一种.NET语言编写(至少,你可以在CIL中编写),它确实有一个实际上有效的无参数构造函数。由于这个原因,这种语言的编译器可能希望它等效于new SomeValueType()来调用数组中所有类型的构造函数。因此,在框架中使用允许完成此类填充的方法是明智的,这样这种语言的编译器就可以使用它。

  

另外,为什么要公开?

因此,即使在安全限制阻止它调用另一个程序集的私有方法的上下文中,也可以通过这种假设构造函数生成的代码调用它。

答案 1 :(得分:1)

对我来说,看起来Initialize()方法在数组中运行并重新创建 Value Types 。因此,使用 new array ,您将获得一个新的空数组,因此您可以使用 Array.Clear(),但使用 Array.Initialize()你得到一个完整的值类型的数组(基于旧数组的类型和长度)。

这应该是完全不同的。

答案 2 :(得分:0)

基于CLR source,该方法遍历数组的每个索引,并通过调用默认构造函数初始化该索引上的值类型,类似于initobj IL指令(我想知道当虽然构造函数抛出异常。该方法是公开的,因为直接从IL调用私有方法会使它有点无法验证。

今天的C#编译器在创建时不会初始化数组的每个元素,只需"设置"每个索引到该类型的默认值。 C#6引入了实现值类型的默认构造函数(CLR已经支持),因此具有不同数组创建语义的语言需要这样做。

答案 3 :(得分:0)

您可以在测试代码中看到预期用途:

https://github.com/dotnet/coreclr/blob/3015ff7afb4936a1c5c5856daa4e3482e6b390a9/tests/src/CoreMangLib/cti/system/array/arrayinitialize.cs

基本上,它将非内在值类型的数组设置回其默认(T)状态。

它似乎不是一个非常有用的工具,但我可以看到它如何有效地将非内在价值数据的数组归零。