引用类型的未初始化与空值
未初始化的引用类型变量和具有 null 值之间有区别吗? 我在某处读到非 init 意味着 null,但在其他地方我读到了其他内容。谢谢!
Is there a difference between reference type variable being non initialized or having null value?
I read somewhere that non-init means null but on other place I read something else. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请注意,字段隐式初始化为
null
,因此这只影响变量。在纯 C# 中,您无法查询未初始化字段的值(您需要“明确赋值”),因此这是没有问题的。不过,您可以通过滥用 IL 来做到这一点 - 通过声明
out
参数,并使用DynamicMethod
编写一个不分配该参数的方法(在 IL 中有效,但在 C# 中无效)。然后你会发现你会看到null
。这又是由于 调用 (C#) 代码上的 IL 标志 (
.locals init
) 表示“在进入此方法之前清除堆栈”。 C# 编译器始终设置此标志。如果您再次滥用 IL 来编写不设置此标志的方法,您可能会看到垃圾。它可以是任何东西。但到了这一点,你应该得到你得到的例外:)这是第一个示例(不是第二个,第二个更复杂):
为了澄清起见,
DynamicMethod
代码只是编写了与此等效的代码代码,在 C# 中不合法:这是有效的,因为就 CLR 而言
out
不存在 - 只有ref
。因此,这不是无效的 IL - 它只是语言 (C#) 赋予out
含义并要求为其分配一个值。问题是
Main()
仍然具有.locals init
标志;所以在幕后obj
被清除为null
(好吧,整个堆栈空间被简单地擦除)。如果我在没有该标志的情况下从 IL 进行编译(并且有一些其他代码使堆栈空间变脏),我可以看到垃圾。您可以在 Liran Chen 的 上查看有关.locals init
的更多信息a> 博客。但要回答这个问题:
null
- 由null
即使你不能问;pNote that fields are implicitly initialized to
null
, so this only affects variables. In pure c# you can't query the value of an uninitialized field (you need "definite assignment"), so it is a non-question.You can do this by abusing IL though - by declaring an
out
parameter, and usingDynamicMethod
to write a method that doesn't assign it (valid in IL, but not in C#). And then you find that you will seenull
s.This in turn is due to an IL flag (
.locals init
) that says "clear the stack for me before entering this method" on the calling (C#) code. The C# compiler always sets this flag. If you again abuse IL to write a method that doesn't set this flag, you can probably see garbage. It could be anything. But by this point, you deserve the exceptions you get :)Here's an example of the first (not the second, which is more complex):
For clarification, the
DynamicMethod
code is simply writing the equivalent of this code, not legal in C#:This works because as far as the CLR is concerned
out
doesn't exist - there is onlyref
. So this isn't invalid IL - it is only the language (C#) that puts meaning toout
and demands that it be assigned a value.The problem is that
Main()
still has the.locals init
flag; so behind the scenesobj
is cleared tonull
(well, the entire stack space is simply wiped). If I compiled from IL without that flag (and had some other code in place to make the stack space dirty) I could see garbage. You can see more about.locals init
on Liran Chen's blog.But to answer the question:
null
- guaranteed by the specnull
even though you can't ask ;p“这取决于”
对于普通成员变量,当声明中未指定值时,该变量将采用适当的默认值(对于引用类型为
null
)。即,class A { string X; }
与class A { string X = null; 相同}
。对于局部变量,在可以证明值已被分配之前访问它们是错误的。尽管它们的类型“默认”为 null(对于引用类型),但它们并不是默认隐式分配的!即,
string F () { string x;返回x; }
是一个编译时错误。请记住:
null
是null
:-)"It depends"
For normal member variables when a value is not specified in the declaration then the variable assume the appropriate default value (
null
for reference types). That is,class A { string X; }
is the same asclass A { string X = null; }
.For local variables it is an error to access them before a value can be proven to have been assigned. Even though their type "defaults" to null (for reference types), they are not default implicitly assigned! That is,
string F () { string x; return x; }
is a compile-time error.Remember:
null
isnull
:-)