【发布时间】:2011-06-13 19:33:00
【问题描述】:
引用类型变量未初始化或具有空值之间有区别吗? 我在某处读到非初始化意味着 null,但在其他地方我读到了别的东西。谢谢!
【问题讨论】:
引用类型变量未初始化或具有空值之间有区别吗? 我在某处读到非初始化意味着 null,但在其他地方我读到了别的东西。谢谢!
【问题讨论】:
注意 fields 被隐式初始化为null,所以这只影响变量。在纯 c# 中,您无法查询未初始化字段的值(您需要“明确赋值”),因此这是一个非问题。
你可以通过滥用 IL 来做到这一点 - 通过声明一个 out 参数,并使用 DynamicMethod 编写一个不分配它的方法(在 IL 中有效,但在C#)。然后你发现你会看到nulls。
这又是由于 调用 (C#) 代码中的 IL 标志 (.locals init) 表示“在进入此方法之前为我清除堆栈”。 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【讨论】:
null。他还说实际上C#编译器没有必要禁止使用非初始化变量,但是编译器还是有这个限制的。
.locals init 标志驱动的。 IIRC 你可以省略这个,让混乱开始。
“视情况而定”
对于普通的成员变量,当声明中未指定值时,该变量采用适当的默认值(引用类型为null)。即class A { string X; }与class A { string X = null; }相同。
对于局部变量,在可以证明已分配值之前访问它们是错误的。即使它们的类型“默认”为 null(对于引用类型),它们也不是默认隐式分配的!也就是说,string F () { string x; return x; } 是编译时错误。
记住:null 是 null :-)
【讨论】: