C# 如果不使用new关键字生成结构,会发生什么情况?
如果不使用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
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
字节,值为零;非常便宜,同时仍然保持安全的默认值。无需初始化2000Person
实例,2000int
实例和2000string
实例-默认情况下它们都为零。同时,您不可能为字符串
引用获得指向内存中某个随机位置的随机值(非托管代码中非常常见的错误)
要求显式初始化局部变量的主要原因是它可以防止愚蠢的编程错误。你不应该首先访问一个未初始化的值,如果你需要一个默认值,你应该明确它-默认值然后得到一个含义,含义应该是明确的。您会发现,可以首先有意义地使用未初始化的局部的情况非常罕见—您通常要么在获取值的地方声明局部,要么需要所有可能的分支来更新预先声明的局部。这两种方法都可以使代码更容易理解,并避免愚蠢的错误。无论包含的数据结构如何,by类型都适用。除了知道这一点之外,这仅仅是因为您对实现感到好奇吗?对我来说似乎很学术。@DonBoitnott你能检查一下我对这个问题的编辑吗?谢谢这两种情况都有错误,错误只是略有不同。它很可能与运行时中微小的实现细节有关-属性访问器是一种必须在(未初始化的)对象上调用的方法,而结构字段是直接(通过