声明一个数组类型

8

在 Stack Overflow 讨论另一个问题时,有人告诉我关于语法

int[] numbers = new int[10];

比...更好
Array numbers = Array.CreateInstance(typeof(int), 10);

我的问题是,第一种语法在什么情况下有用,第二种语法在什么情况下有用?为什么?


7
当您在编译时知道类型时,我无法看到使用第二种形式的任何好处。 - Jon Skeet
1
与大多数类不同,数组提供CreateInstance方法而非公共构造函数,以允许进行后期绑定访问。- Array.CreateInstance 方法 - Habib
@asawyer 他们是如何做不同的事情的?他们产生完全相同的效果,除了返回类型可能会有所不同。 - nawfal
@asawyer 但它们真的不同吗?在两者上运行GetType(),它们只是相同的。这只是一个问题如何输入。而这只是将其转换为其原始类型的问题。即使它们仍然不同,它们并不完全不同。在“哺乳动物”伪装下的CatCat是否完全不同? - nawfal
@nawfal 对于编译时静态分析,是的,它们是不同的。 - asawyer
显示剩余3条评论
4个回答

8
这将直接创建一个强类型的一维数组:
int[] array = new int[10];

在底层,它使用IL命令newarr

这种方式更类似于使用反射来创建数组(类型可以在运行时决定)。

int[] array2 = (int[])Array.CreateInstance(typeof(int), 10);

使用Array.CreateInstance创建的数组与直接创建的数组相同,但创建速度要慢得多。需要注意的是,使用Array.CreateInstance可以动态选择数组的类型(就像通过反射可以在运行时根据类型创建实例一样),例如:
Type type = someCondition ? typeof(int) : typeof(string);
Array array2 = Array.CreateInstance(type, 10);

另一个重要的区别是,“基础”Array类是弱类型的(因此其方法使用object参数,而不是int/string/'something')。所以:
int num = (int)array2.GetValue(1); // You have to cast the return value to int from object

另一个使用的原因是:

array[5] = 1;

代替
array2.SetValue(5, 1);

第一种方法在IL代码中被优化为对单维数组(stelemldelem)的直接访问。同样适用于GetValue


我使用“单维数组”这个术语的原因:

在.NET中有两种“类型”的数组: 单维数组和“复杂”数组(它们可以是多维的,或者第一个元素不在0索引处,或这两种情况都有)。第二组要慢得多。stelemldelem仅适用于单维数组。对于多维/特殊数组,会使用“隐藏的”方法来访问它们(C#编译器会更改get和set,以便调用这些方法)(它们类似于Array类的GetValue/SetValue,例如https://dev59.com/dnRB5IYBdhLWcg3wiHll#597729)。


谢谢,这回答了我的问题,并且让我了解了IL代码的内部。这正是我在寻找的。已接受! - TheSilverBullet

5
在编译时,它们之间似乎没有太大的区别。就像数组一样,Array.CreateInstance 方法也会将引用类型元素初始化为 null,值类型元素初始化为 zero

enter image description here

第二个不同之处在于;来自MSDN

与大多数类不同,数组提供了CreateInstance方法而不是公共构造函数,以允许进行后期绑定访问。

正如Stefano Altieri 提到的那样,第一种语法需要在编译时指定数组大小,但第二种需要在运行时指定大小。例如,您可以成功构建这些代码;

int[] numbers1 = new int[10];
Array numbers2 = Array.CreateInstance(typeof(int), -1);

但你无法建造这些;

int[] numbers1 = new int[];
Array numbers2 = Array.CreateInstance(typeof(int), -1);

1
我不确定我会说返回 int[10] 和返回 Array 的表达式之间“没有区别”。 - asawyer
1
感谢提供的可视化,非常有帮助。如果您查看“类型”列,您会发现这两个声明确实是不同的。 - TheSilverBullet

4
你写的样例是等价的。关键在于,使用第一种语法(new int[size])需要在编译时知道数组类型。
第二种语法允许你在运行时决定数组项的类型,这远比第一种更强大,但并非总是必需的。例如:
Type myType = SelectTheBestType();
var numbers = Array.CreateInstance(myType, 10);

2

Soner Gönül的回答非常好。简单来说,如果将数组作为对象或接口传递,则编译时元素类型未知。

[这个答案]可能会给您带来一些想法,[这里]有一些示例代码。

第一个语法何时有用,第二个语法何时有用?

链接中的方法,

static IList CreateArray<T>(this T source);

因为我不能假设source必须是一个数组,但它仍然可能是一个数组,所以通用类型参数是T而不是T[]。因此我只能在方法内部使用Array.CreateInstance

大多数情况下,如果元素类型在编译时已知,则最好使用语言提供的语法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接