开发者

Non-initialized vs null values of reference types

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 r开发者_运维问答ead something else. Thanks!


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.

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.

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);
}

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

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.

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.

But to answer the question:

  • 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 depends"

For normal member variables when a value is not specified in the declaration then the variable assume the appropriate default value (null for reference types). That is, class A { string X; } is the same as class A { string X = null; }.

For local variables it is an error to access them before a value can be proven to have been assigned. Even though their type "defaults" to null (for reference types), they are not default implicitly assigned! That is, string F () { string x; return x; } is a compile-time error.

Remember: null is null :-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜