引用类型的未初始化与空值 [英] Non-initialized vs null values of reference types

查看:58
本文介绍了引用类型的未初始化与空值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

引用类型变量未初始化或具有空值之间有区别吗?我在某处读到 non-init 意味着 null 但在其他地方我读到了别的东西.谢谢!

Is there a difference between reference type variable being non initialized or having null value? I read somewhere that non-init means null but on other place I read something else. Thanks!

推荐答案

注意 fields 被隐式初始化为 null,所以这只影响变量.在纯 C# 中,您无法查询未初始化字段的值(您需要明确赋值"),因此它不是问题.

Note that fields are implicitly initialized to null, so this only affects variables. In pure c# you can't query the value of an uninitialized field (you need "definite assignment"), so it is a non-question.

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

You can do this by abusing IL though - by declaring an out parameter, and using DynamicMethod to write a method that doesn't assign it (valid in IL, but not in C#). And then you find that you will see nulls.

这又是由于一个 IL 标志 (.locals init) 在 调用 (C#) 上说在进入此方法之前为我清除堆栈"代码.C# 编译器始终设置此标志.如果您再次滥用 IL 编写未设置此标志的方法,您可能会看到垃圾.它可以是任何东西.但此时,你应该得到例外:)

This in turn is due to an IL flag (.locals init) that says "clear the stack for me before entering this method" on the calling (C#) code. The C# compiler always sets this flag. If you again abuse IL to write a method that doesn't set this flag, you can probably see garbage. It could be anything. But by this point, you deserve the exceptions you get :)

这是第一个示例(不是第二个,后者更复杂):

Here's an example of the first (not the second, which is more complex):

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# 中不合法:

For clarification, the DynamicMethod code is simply writing the equivalent of this code, not legal in C#:

static void Foo(out object whatever) { } // note, whatever is not assigned

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

This works because as far as the CLR is concerned out doesn't exist - there is only ref. So this isn't invalid IL - it is only the language (C#) that puts meaning to out and demands that it be assigned a value.

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

The problem is that Main() still has the .locals init flag; so behind the scenes obj is cleared to null (well, the entire stack space is simply wiped). If I compiled from IL without that flag (and had some other code in place to make the stack space dirty) I could see garbage. You can see more about .locals init on Liran Chen's blog.

但是要回答这个问题:

  • 对于字段:未初始化的引用类型字段为 null - 由规范保证
  • 对于变量:你不能问,但作为一个实现细节(不应该依赖):是的,它将是null 即使你不能问;p
  • for fields: uninitialized reference-type fields are null - guaranteed by the spec
  • for variables: you can't ask, but as an implementation detail (that should not be depended on): yes, it will be null even though you can't ask ;p

这篇关于引用类型的未初始化与空值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆