为啥 C# 局部变量应该直接赋值,即使它是默认值?
Posted
技术标签:
【中文标题】为啥 C# 局部变量应该直接赋值,即使它是默认值?【英文标题】:Why C# local variable should be assigned directly, even if it's default value?为什么 C# 局部变量应该直接赋值,即使它是默认值? 【发布时间】:2014-02-08 05:15:45 【问题描述】:如果你看下一个例子:
public void TestLocalValuesAssignment()
int valueVariable; // = default(int) suits fine
string refType; // null suits fine as well
try
valueVariable = 5;
refType = "test";
catch (Exception)
Console.WriteLine("int value is 0", valueVariable);
Console.WriteLine("String is 0", refType);
您可以很容易地看到,变量valueVariable
和refType
在Console.WriteLine()
中使用之前可能会被取消分配。编译器通过错误告诉我们:
Error 1 Use of unassigned local variable 'valueVariable'
Error 2 Use of unassigned local variable 'refType'
这是一个普遍的案例,有 loads of answers 关于如何解决这个问题(可能的修复已评论)。
我不明白为什么会存在这种行为? 这里的局部变量与类字段有何不同,最后一个变量在未分配的情况下获得默认值(引用类型为 null,值类型为对应的默认值)?也许有一个例子或一个极端案例来解释为什么选择这种编译器行为?
【问题讨论】:
Initialization of instance fields vs. local variables的可能重复 这不是“行为”,而是规则。明确赋值规则规定变量必须在使用前被赋值。显然,当引发异常时,它不会出现在您的代码 sn-p 中。是的,有可能发生。 @TimSchmelter 完全同意,这是重复的。 John Skeet provided 相当合理的解释,可以视为对我问题的回答。 【参考方案1】:基本上 - 这是 MS 决定的。
如果您想了解更多信息,可以阅读here 并查看Eric Lippert’s Blog
这在 C# 中是非法的原因是因为使用未分配的本地很可能是一个错误。
【讨论】:
该链接指向一个很棒的 Eric Lippert 答案。 同意,Eric Lippert 的回答解释了很多。基本上,这似乎是防止程序员犯错误的规则。 @Antonio:对。基本上,这个想法是(1)未初始化的变量很可能是错误,(2)当一个局部没有被明确分配时很容易检测到,但是当一个字段没有被明确分配时检测起来就相当困难了.因此,规则是:必须明确分配本地人。如果找到未分配的字段既便宜又容易,那么该规则也将扩展到字段,但这并不便宜和容易。【参考方案2】:在c#规范中有描述:
5.1.7 局部变量
由 local-variable-declaration 引入的局部变量不是 自动初始化,因此没有默认值。为了 明确赋值检查的目的,引入了一个局部变量 local-variable-declaration 最初被认为是未分配的。一种 local-variable-declaration 可以包含一个 local-variable-initializer, 在这种情况下,变量被认为是明确分配的 在初始化表达式之后(第 5.3.3.4 节)。
在由 a 引入的局部变量的范围内 local-variable-declaration,这是一个编译时错误参考 该局部变量位于其之前的文本位置 本地变量声明符。如果局部变量声明是 隐式(第 8.5.1 节),引用其中的变量也是错误的 它的local-variable-declarator。
【讨论】:
是的,很好的参考。它清楚地解释了编译器的行为(或规则)。虽然它没有解释为什么做出这样的决定。我希望得到一些例子,说明为什么存在这条规则。【参考方案3】:当你做了一些看起来很愚蠢的事情,比如从一个你从未分配过的变量中读取,编译器基本上可以做两件事:
-
为您提供诊断,提醒您注意可能存在的错误。
随心所欲。
由于选项 #1 可以帮助您发现错误,因此它是首选,尤其是当告诉编译器“不,我的意思是使用原始默认值”的解决方法就像添加 = 0
、= null
或 @ 一样简单987654323@.
至于为什么类成员的工作方式不一样,是因为在编译时无法检查(因为可以调用不同方法的无数不同的顺序)。是否已分配每个成员以及测试这些标志都会产生标志的运行时成本。
请注意,编译器确实以一种易于在编译时检查的方式强制执行对结构成员的限制。也就是说,每个构造函数都需要分配每个成员。
【讨论】:
【参考方案4】:实际上,您的代码应该没问题,但通过严格解释,有一个代码路径可以让您的变量在使用前未分配。 try 块引入了块内的代码可能不被执行(如果抛出异常),但仍然执行 catch 之外的代码(因为没有在 catch 中,例如 return 或 throw 以防止在 try)。
如果你指的是初始化“struct”字段和初始化类字段的区别,例如:
public class A
MyMethod()
int myInt; // Initialized to zero, yes, but not yet assigned.
// An error to use this before assigning it.
A myA; // defaults to null, which may be a valid initial state, but still unassigned.
// Also an error to use this before assigning it.
A oneMoreA = null; // Same value as default, but at least intention is clear.
A anotherA = new A(); // What is or is not happening in the constructor is a separate issue.
// At least anotherA refers to an actual instance of the class.
【讨论】:
以上是关于为啥 C# 局部变量应该直接赋值,即使它是默认值?的主要内容,如果未能解决你的问题,请参考以下文章