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 null
s.
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
:-)
精彩评论