未初始化或具有空值的引用类型变量之间是否存在差异? 我读到某处非初始化意味着null,但在其他地方我读了别的东西。谢谢!
答案 0 :(得分:15)
请注意,字段会隐式初始化为null
,因此这只会影响变量。在纯c#中你无法查询未初始化字段的值(你需要“明确赋值”),所以这是一个非问题。
你可以通过滥用IL来做到这一点 - 通过声明out
参数,并使用DynamicMethod
编写一个不分配它的方法(在IL中有效) ,但不是在C#中。然后你会发现你会看到null
s。
这反过来是由于IL标志(.locals init
)在调用(C#)代码上显示“在输入此方法之前为我清除堆栈”。 C#编译器始终设置此标志。如果你再次滥用IL来编写一个没有设置此标志的方法,你可能会看到垃圾。它可能是任何东西。但是到目前为止,你应该得到例外情况:)
这是第一个例子(不是第二个,更复杂):
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#中不合法:
static void Foo(out object whatever) { } // note, whatever is not assigned
这是因为就CLR而言 out
不存在 - 只有ref
。所以这不是无效的IL - 只有语言(C#)赋予out
意义并要求为其赋值。
问题是Main()
仍然有.locals init
标志;所以在幕后obj
被清除到null
(好吧,整个堆栈空间都被擦掉了)。如果我从没有那个标志的IL编译(并且有一些其他代码来使堆栈空间变脏)我可以看到垃圾。您可以在Liran Chen's博客上看到有关.locals init
的更多信息。
但要回答这个问题:
null
- 由规范保证null
即使你也不能问; p 答案 1 :(得分:3)
“这取决于”
对于普通的成员变量,当声明中未指定值时,该变量将采用适当的默认值(null
作为参考类型)。也就是说,class A { string X; }
与class A { string X = null; }
相同。
对于局部变量,在证明已分配值之前访问它们是错误的。即使它们的类型“默认”为null(对于引用类型),它们也不是默认隐式赋值的!也就是说,string F () { string x; return x; }
是编译时错误。
请记住:null
是null
: - )