【问题标题】:Why doesn't a struct in an array have to be initialized?为什么不必初始化数组中的结构?
【发布时间】:2018-07-22 05:56:51
【问题描述】:

我研究了这个主题,但找不到任何重复项。我想知道为什么您可以在数组中使用 struct 而无需创建它的实例。

例如,我有一个class 和一个struct

public class ClassAPI
{
    public Mesh mesh { get; set; }
}

public struct StructAPI
{
    public Mesh mesh { get; set; }
}

在数组中使用ClassAPI 时,必须使用new 关键字对其进行初始化,然后才能使用其属性和方法:

ClassAPI[] cAPI = new ClassAPI[1];
cAPI[0] = new ClassAPI(); //MUST DO THIS!
cAPI[0].mesh = new Mesh();

StructAPI 并非如此。看起来StructAPI 不必在数组中初始化:

StructAPI[] sAPI = new StructAPI[1];
sAPI[0].mesh = new Mesh();

如果你用ClassAPI 尝试同样的事情,你会得到一个NullReferenceException

为什么在数组中使用结构时会有所不同?

我理解classstruct 之间的区别,struct 是一个值类型,但这仍然没有意义。对我来说,如果没有数组参与,看起来我正在这样做:

StructAPI sp;
sp.mesh = new Mesh();

请注意,sp 变量未初始化,它应该会导致编译时错误:

错误 CS0165 使用未分配的局部变量“sp”

但当struct 被放入一个数组时,情况就不同了。

数组中是否初始化了struct?我想知道发生了什么。

【问题讨论】:

  • Specification:为了明确赋值检查,数组元素被认为是初始赋值的。
  • @PetSerAl 这是有道理的。所以它正在为数组中的每个项目做类似StructAPI sp = default(StructAPI); 的事情?如果是这样,它是编译时的还是运行时的?
  • 你能使用其他值类型的变量,比如int,在C#中未初始化吗?如果不是,这是相同的想法。 new int[5] 全为零。 (我更多地使用 VB.NET,Dim sp As StructAPI : sp.mesh = New Mesh() 会发出警告但工作正常。)
  • @Programmer:听到这个我很惊讶。
  • @Programmer 那是因为你使用了属性。属性访问器只是一个方法,方法不能在未完全初始化的结构体上调用。但是即使结构没有初始化,也可以分配字段。

标签: c# arrays unity3d struct


【解决方案1】:

根据 PetSerAl 在 cmets 中提供的specification link

数组元素
数组的元素在创建数组实例时开始存在,当没有对该数组实例的引用时不再存在。

数组中每个元素的初始值是数组元素类型的默认值(Default values)。

为了明确分配检查,数组元素被认为是初始分配的。

(强调我的)。

这意味着当您声明一个T 数组时,数组中的每个“单元格”都将使用default(T) 进行初始化。对于引用类型 default(T) 返回 null,但对于值类型 default(T) 返回类型默认值 - 0 用于数字,false 用于 bool,等等。

根据Using Structs (C# Programming Guide) 页面:

如果使用默认的无参数构造函数实例化结构对象,则所有成员都根据其默认值分配。

由于结构是值类型,default(T) 其中T 是一个结构,它将结构初始化为其默认值,这意味着它的所有成员将被初始化为其默认值——null 用于引用类型和任何默认值值类型。

所以这行代码StructAPI[] sAPI = new StructAPI[1]; 基本上创建了一个新的StructAPI 数组,其中包含一个StructAPI 实例,其中它的mesh 属性是default(Mesh)

【讨论】:

  • “对于引用类型 default(T) 返回 null,但对于值类型 default(T) 返回类型默认值” 不知道 default 的行为带有引用和值类型。虽然,我在阅读PetSerAl's 评论后怀疑default 在其中发挥了作用。
  • 是的,总结一下:-)
【解决方案2】:

这可能是因为类,虽然它们确实有一个默认构造函数,但结构实际上没有一个。

为什么类数组需要初始化

类创建对象,然后返回引用。实际变量是对该值的引用。默认值始终为零,因此引用的默认值是null,因为null 由全为零的地址表示,这意味着它不指向任何东西。

正因为如此,一个类的数组的默认值都是空引用。

为什么不需要 struct 数组

另一方面,结构都是按值计算的。它们也没有默认的无参数构造函数,并且 C# 不允许您创建一个(尽管 CLR 可以)。由于没有构造函数,CLR 能够通过将所有值清零来非常有效地创建结构,而无需调用构造函数。

您可以从this StackOverflow 问题中查看有关此问题的更多信息。

【讨论】:

    【解决方案3】:

    当你初始化一个数组时,默认值被分配给它的元素

    • null 引用类型,
    • 对于值类型,默认值不同:表示数字的类型为零,对于struct,它有点不同,它的默认值是struct,所有字段都设置为默认值。同样,对于引用类型,它是 null,对于值类型,它取决于(如上所述)。

    因此,基本上,当您初始化数组时,您的 structs 已初始化(设置为默认值),这就是您可以访问它们的属性的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-22
      • 1970-01-01
      • 2013-08-07
      • 1970-01-01
      相关资源
      最近更新 更多