user1017882
user1017882

Reputation:

Why did this compile?

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

Answers (3)

György Kőszeg
György Kőszeg

Reputation: 18013

First of all, code editor aids might give you a warning that the field is not assigned and it may work wrong.

enter image description here.

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

Rob
Rob

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

Gimly
Gimly

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

Related Questions