Reputation:
The code below compiled without a problem. It's clear _dependency
will always be null
, so it's not possible to use it in any way (aside from evaluating it) - is it? Why was the compiler not aware of this and fail it?
public class MyClass
{
private readonly MyDependency _dependency;
public MyClass()
{
_dependency.MyMethod();
}
}
To be clear, I know the code above is bad code, and it is the developers fault - but as is any other compile-time error. I would've thought the compiler would've thrown a use of unassigned variable
kind of error.
Why did this compile? Am I unaware of a scenario whereby it would be fine to use a null
object like this?
EDIT:
To confirm - I am not wishing to rely on the compiler to check for poorly written code - and I appreciate that, syntactically, it is absolutely fine. My question really is two-fold, is there a scenario which I'm unaware of which may make this code execute fine. And the second question is - why wouldn't it detect such an issue, if it already deals with use of unassigned variable
errors? What's the difference?
Upvotes: 3
Views: 108
Reputation: 18013
First of all, code editor aids might give you a warning that the field is not assigned and it may work wrong.
Secondly, you cannot test in compile time whether the members are accessed by reflection. You can assign the field, even if it is read-only. You can even invoke the constructor after you initialized the read-only field externally. Consider the following example:
// creating an instance without executing the constructor
MyClass myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass));
// setting the read-only field
myClass.GetType().GetField("_dependency", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(myClass, new MyDependency());
// invoking the constructor on the already existing myClass
ConstructorInfo ctor = typeof(MyClass).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
MethodInfo mi = typeof(RuntimeMethodHandle).
GetMethod("InvokeMethod", BindingFlags.NonPublic | BindingFlags.Static);
object signature = ctor.GetType().GetProperty(
"Signature", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(ctor);
mi.Invoke(null, new []{myClass, null, signature, false});
Upvotes: 1
Reputation: 27357
Because it's not strictly incorrect. Maybe a warning, but definitely not a compiler error.
You can do this for example:
public class MyClass
{
private readonly MyDependency _dependency;
public MyClass()
{
_dependency.MyMethod();
}
public bool IsDependencyNull()
{
return _dependency == null;
}
}
public class MyDependency { public void MyMethod() { } }
Then using it:
var c = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass));
c.IsDependencyNull().Dump();
Gives the result 'True'
Upvotes: 2
Reputation: 6175
Because the compiler doesn't check for that kind of issues. It's syntactically correct, and perfectly fine. Null reference issues are usually only detected on runtime, unless you use code analysis tools that will detect that kind of issues.
Upvotes: 7