引用类型的未初始化与空值 [英] Non-initialized vs null values of reference types
问题描述
引用类型变量未初始化或具有空值之间有区别吗?我在某处读到 non-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!
推荐答案
注意 fields 被隐式初始化为 null
,所以这只影响变量.在纯 C# 中,您无法查询未初始化字段的值(您需要明确赋值"),因此它不是问题.
Note 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.
你可以通过滥用 IL 来做到这一点 - 通过声明一个 out
参数,并使用 DynamicMethod
编写一个不分配它(在 IL 中有效,但在 C# 中无效).然后你发现你会看到null
s.
You can do this by abusing IL though - by declaring an out
parameter, and using DynamicMethod
to write a method that doesn't assign it (valid in IL, but not in C#). And then you find that you will see null
s.
这又是由于一个 IL 标志 (.locals init
) 在 调用 (C#) 上说在进入此方法之前为我清除堆栈"代码.C# 编译器始终设置此标志.如果您再次滥用 IL 编写未设置此标志的方法,您可能会看到垃圾.它可以是任何东西.但此时,你应该得到例外:)
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):
delegate void AbuseMe(out object foo);
static void Main() {
DynamicMethod dyn = new DynamicMethod("Foo",
typeof(void), new[] { typeof(object).MakeByRefType() });
dyn.GetILGenerator().Emit(OpCodes.Ret);
AbuseMe method = (AbuseMe) dyn.CreateDelegate(typeof(AbuseMe));
object obj; // this **never** gets assigned, by **any** code
method(out obj);
Console.WriteLine(obj == null);
}
为了澄清,DynamicMethod
代码只是编写了此代码的等效代码,在 C# 中不合法:
For clarification, the DynamicMethod
code is simply writing the equivalent of this code, not legal in C#:
static void Foo(out object whatever) { } // note, whatever is not assigned
这是可行的,因为就 CLR 而言 out
不存在 - 只有 ref
.所以这不是无效的 IL - 只有语言 (C#) 赋予 out
意义并要求为其分配一个值.
This works because as far as the CLR is concerned out
doesn't exist - there is only ref
. So this isn't invalid IL - it is only the language (C#) that puts meaning to out
and demands that it be assigned a value.
问题是 Main()
仍然有 .locals init
标志;所以在幕后 obj
is 被清除为 null
(好吧,整个堆栈空间都被简单地擦除了).如果我在没有那个标志的情况下从 IL 编译(并且有一些其他代码来使堆栈空间变脏),我会看到垃圾.你可以在陈立然的上看到更多关于.locals init
的信息a> 博客.
The problem is that Main()
still has the .locals init
flag; so behind the scenes obj
is cleared to null
(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.
但是要回答这个问题:
- 对于字段:未初始化的引用类型字段为
null
- 由规范保证 - 对于变量:你不能问,但作为一个实现细节(不应该依赖):是的,它将是
null
即使你不能问;p
- for fields: uninitialized reference-type fields are
null
- guaranteed by the spec - for variables: you can't ask, but as an implementation detail (that should not be depended on): yes, it will be
null
even though you can't ask ;p
这篇关于引用类型的未初始化与空值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!