提问者:小点点

当不使用new关键字创建结构时会发生什么?


当不使用new关键字创建结构时,幕后会发生什么?

假设我们有这样的结构:

struct Person
{
    public int Age;
    public string Name;
}

在Main()方法中,我决定创建一个不带new关键字的实例,如下所示:

Person p;

现在,如果我试图访问p.age,我将得到一个编译时错误,说“使用可能未赋值的字段'age'”,但是如果我像这样创建一个结构实例:

Person p = new Person();

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

编辑:谁也能解释这个行为吗?代码:

struct Person
{
    public string Name { get; set; }

}

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

Person p;

我手动初始化名称

p.Name = "SomeRandomName"';

我就不能用了。编译器给出一个错误“Use of an unassigned local variable P”,但如果我用默认(无参数)构造函数创建结构实例,就不会出现这样的错误。


共3个答案

匿名用户

如果您阅读小型结构文档,您可以引用:

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

通常,当您在代码中声明这些类型时,类似于:

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

您创建的是一个值类型,默认情况下它没有初始化,您不能访问它的属性。因此,您不能将其声明为:

Person p;

然后直接使用它。br>因此出现错误:

“使用可能未分配的字段'age'”

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

我就不能用了。编译器给出一个错误“Use of an unassigned local variable P”,但如果我用默认(无参数)构造函数创建结构实例,就不会出现这样的错误。

不能直接分配的同样原因是仍未初始化。

必须创建结构的新实例为

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

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

匿名用户

会员和本地人的规则不一样。

在使用之前必须显式初始化局部变量。成员由运行库初始化为各自的默认值。

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

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

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

匿名用户

。NET中的每个数据类型都有一个默认值。对于所有引用类型,它都是空的。对于特殊类型字符串,它也为NULL。对于所有的值类型,它都类似于零。对于布尔,它是false,因为这等于零。

在编写带有成员字段的类时,可以观察到相同的行为。在构建之后,所有这些字段都将有一个默认值,即使在构建期间没有赋值。

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

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