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

Loj*_*jol 7 c# null reference

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

Mar*_*ell 15

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

可以通过滥用IL 做到这一点 - 通过声明一个out参数,并使用DynamicMethod写一个不分配它的方法(在IL中有效,但在C#中没有).然后你会发现你会看到nulls.

这反过来是由于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);
}
Run Code Online (Sandbox Code Playgroud)

为了澄清,DynamicMethod代码只是编写相当于此代码的代码,在C#中不合法:

static void Foo(out object whatever) { } // note, whatever is not assigned
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为就CLR而言 out并不存在 - 只有ref.所以这不是无效的IL - 只有语言(C#)赋予意义out并要求为其赋值.

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

但要回答这个问题:

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

  • 好的,这真是太怪异了!:) (2认同)