C# 如果不使用new关键字生成结构,会发生什么情况?

C# 如果不使用new关键字生成结构,会发生什么情况?,c#,C#,如果不使用new关键字创建结构,在幕后会发生什么 假设我们有这个结构: struct Person { public int Age; public string Name; } 在Main()方法中,我决定创建一个没有new关键字的实例,如下所示: Person p; Person p = new Person(); Person p; 现在,如果我尝试访问p.Age,我会得到一个编译时错误,说“使用可能未赋值的字段‘Age’”,但是如果我创建这样的结构实例: Pers

如果不使用new关键字创建结构,在幕后会发生什么

假设我们有这个结构:

struct Person
{
    public int Age;
    public string Name;
}
在Main()方法中,我决定创建一个没有new关键字的实例,如下所示:

Person p;
Person p = new Person();
Person p;
现在,如果我尝试访问p.Age,我会得到一个编译时错误,说“使用可能未赋值的字段‘Age’”,但是如果我创建这样的结构实例:

Person p;
Person p = new Person();
Person p;
然后我尝试访问p。Age,我将得到值0。现在,幕后到底发生了什么?运行时是为我初始化这些变量,还是编译器在编译后将初始化它们的代码放在IL中

编辑: 有人能解释一下这种行为吗 代码:

如果我这样创建struct的实例:

Person p;
Person p = new Person();
Person p;
我手动初始化这个名字

p.Name = "SomeRandomName"';

我不能用它了。编译器给出了一个错误“使用未分配的局部变量p”,但如果我使用默认(无参数)构造函数创建结构实例,则不会出现这样的错误。

在.NET中,每个数据类型都有一个默认值。对于所有引用类型,它都为null。对于特殊类型字符串,它也是null。对于所有的值类型,它都类似于零。对于bool,它是假的,因为这等于零

在编写包含成员字段的类时,可以观察到相同的行为。构建之后,所有这些字段都将具有默认值,即使在构建期间未指定任何字段

当您将结构用作成员时,情况也是如此。由于结构不能为null,因此它也将被初始化,并且它的所有成员(再次)使用它们的默认值

编译器输出的不同之处在于,编译器无法确定您是否通过任何方式初始化了成员字段。但它可以确定您在读取方法变量之前是否设置了该值。从技术上讲,这是不必要的,但由于它减少了编程错误(为什么要读取未编写的变量?),编译器错误会出现。

如果您查看,可以引用:

struct
类型是一种值类型,通常用于封装小组相关变量,例如矩形的坐标或库存中项目的特征

通常,当您在代码中声明这些
value
类型时,如下所示:

int i; // By default it's equal to 0
bool b; // by default it's equal to false.
参考
类型为:

string s; //By default it's null
您创建的
struct
是一种值类型,默认情况下不会初始化,您无法访问其属性。因此,您不能将其声明为:

Person p;
然后直接使用它。
因此,您得到的错误是:

“使用可能未指定的字段‘年龄’”

因为
p
仍未初始化。 这也解释了问题的第二部分:

我不能用它了。编译器给出了一个错误“使用未分配的局部变量p”,但如果我使用默认(无参数)构造函数创建结构实例,则不会出现这样的错误

无法直接分配
p.Name=“something”
的原因与
p
仍未初始化相同

您必须创建结构的新实例作为

Person p = New Person(); //or Person p = default(Person);

现在,当您创建一个新的结构实例而不给
struct
属性赋值时,会发生什么?它们中的每一个都将保留其默认值。例如
Age=0
,因为它是
int
类型。

成员与本地人没有相同的规则

在使用之前,必须明确初始化局部变量。成员由运行时初始化为各自的默认值

如果您想了解更多相关信息:

在内部实现细节(非契约!)中,直到当前的MS.NET Windows运行时对象都在堆上的预调零内存中分配(当然,当它们在堆上时)。所有默认值都是“物理”零,因此您只需要“200个连续字节,值为0”。在许多情况下,这就像要求操作系统提供预调零内存页一样简单。保持内存安全是一种性能折衷方案-您只需执行
new Person[2000]
,即可轻松分配2000个
Person
实例数组,该数组只请求2000*大小的
Person
字节,值为零;非常便宜,同时仍然保持安全的默认值。无需初始化2000
Person
实例,2000
int
实例和2000
string
实例-默认情况下它们都为零。同时,您不可能为
字符串
引用获得指向内存中某个随机位置的随机值(非托管代码中非常常见的错误)


要求显式初始化局部变量的主要原因是它可以防止愚蠢的编程错误。你不应该首先访问一个未初始化的值,如果你需要一个默认值,你应该明确它-默认值然后得到一个含义,含义应该是明确的。您会发现,可以首先有意义地使用未初始化的局部的情况非常罕见—您通常要么在获取值的地方声明局部,要么需要所有可能的分支来更新预先声明的局部。这两种方法都可以使代码更容易理解,并避免愚蠢的错误。

无论包含的数据结构如何,by类型都适用。除了知道这一点之外,这仅仅是因为您对实现感到好奇吗?对我来说似乎很学术。@DonBoitnott你能检查一下我对这个问题的编辑吗?谢谢这两种情况都有错误,错误只是略有不同。它很可能与运行时中微小的实现细节有关-属性访问器是一种必须在(未初始化的)对象上调用的方法,而结构字段是直接(通过