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!
2 Answers
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

- 1,026,079
- 266
- 2,566
- 2,900
-
2Ok, that is pretty freaky sh!t! :) – leppie Jan 22 '11 at 21:09
-
Jeffrey Richter in his book "CLR Via C#, 3rd edition" mentions that variables are always initialized by CLR to `null`. He also says that actually it's not necessary for C# compiler to forbid using non-initialized variables, but the compiler still has this restriction. – Dmitrii Lobanov Jan 22 '11 at 21:13
-
@Dmitry exactly, which is why I stressed "should not be depended on". This behaviour is not defined by the C# spec (it doesn't need to be : the entire scenario is already precluded), so any implementation is valid. "Set the locals to monotonically increasing bytes" would be a perfectly legal implementation ;p – Marc Gravell Jan 22 '11 at 21:16
-
@Dmitry and that CLR "rule" is, unless I am mistaken, driven by the `.locals init` flag. IIRC you can omit this, and let the chaos commence. – Marc Gravell Jan 22 '11 at 21:17
"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
:-)

- 14,520
- 6
- 56
- 80