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

时间:2011-01-22 20:38:33

标签: c# reference null

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

2 个答案:

答案 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; }是编译时错误。

请记住:nullnull: - )