引用类型的非初始化vs空值

引用类型变量之间是否存在未初始化或具有空值的区别? 我读到某处非初始化意味着null,但在其他地方我读了别的东西。 谢谢!

请注意, 字段被隐式初始化为null ,因此这仅影响变量。 在纯c#中你不能查询未初始化字段的值(你需要“明确赋值”),所以这是一个非问题。

可以通过滥用IL 执行此操作 – 通过声明out参数,并使用DynamicMethod编写不分配它的方法(在IL中有效,但在C#中无效)。 然后你会发现你会看到null

这反过来是由于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#)才能赋予意义并要求为其赋值。

问题是Main()仍然有.locals init标志; 所以在幕后obj 清除为null (好吧,整个堆栈空间被简单地擦除)。 如果我从没有那个标志的IL编译(并且有一些其他代码来使堆栈空间变脏)我可以看到垃圾。 你可以在Liran Chen的博客上看到更多关于.locals init 的信息 。

但要回答这个问题:

  • 对于字段:未初始化的引用类型字段为null – 由规范保证
  • 对于变量: 你不能问 ,但作为一个实现细节 (不应该依赖):是的, 即使你不能问,它也会为null ; p

“这取决于”

对于普通成员变量,如果未在声明中指定值,则变量将采用相应的默认值(引用类型为null )。 也就是说, class A { string X; } class A { string X; }class A { string X = null; }相同class A { string X = null; } class A { string X = null; }

对于局部变量 ,在certificate已分配值之前访问它们是错误的。 即使它们的类型“默认”为null(对于引用类型),它们也不是默认隐式赋值的! 即, string F () { string x; return x; } string F () { string x; return x; } 是一个编译时错误。

记住: nullnull 🙂