Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET: Which Exception to Throw When Required Property is Not Set? [duplicate]

Assume I have a class like this:

public class Foo
{
    public Bar RequiredProperty { get; set;}

    public void Baz()
    {
        if (this.RequiredProperty == null)
        {
            // Which exception should I throw?
        }
    }
}

My solution has a class that is designed to be reused without having to pass a lot of arguments to the Bar method over and over again. So, what should I throw when Bar isn't initialized to a non-null value?

More Information I'm essentially rolling my own code parser and formatter. Call it an object lesson. One of the classes is an HtmlCodeFormatter that has the following properties (in honor of Dependency Injection):

public IFormatter Formatter { get; set; }
public IParser Parsre { get; set; }

This allows me to write any number of language-specific parsers and formatters. For example, I have a CSharpParser and a JavascriptParser. I also have an HtmlCodeFormatter, and there are plans for another (of dubious utility).

The idea is that you can instantiate the HtmlFormatter using an object initializer, like this:

var formatter = new HtmlCodeFormatter()
    {
        Parser = new CSharpParser();
        Formatter = new HtmlCodeFormatter();
    };
formatter.Format("Console.WriteLine(\"Hello, world!\"));

When HtmlCodeFormatter.Format is invoked, it needs to be able to verify that both a parser and a formatter have been provided. That's no problem, really, but I'm kind of stumped about which exception to throw. I'm leaning towards InvalidOperationException, but I'm not entirely certain that's the best choice.

like image 629
Mike Hofer Avatar asked Mar 05 '11 19:03

Mike Hofer


2 Answers

I would throw a InvalidOperationException. The MSDN definition is:

The exception that is thrown when a method call is invalid for the object's current state.

However, i recommend using constructor injection instead of setter injection. This makes sure you has valid parsers and formatters. If null is passed in the constructor, throw a ArgumentNullException.

like image 70
alexn Avatar answered Sep 18 '22 10:09

alexn


By using Propery Injection you are implicitly telling the compiler, fellow developers as well as DI Containers that the dependency is optional. This is because no-one forces you to assign a property value.

If the dependency is truly required, you should refactor to Constructor Injection. This will effectively make the dependency required:

public class Foo
{
    private readonly Bar bar;

    public Foo(Bar bar)
    {
        if (bar == null)
        {
            throw new ArgumentNullException("bar");
        }

        this.bar = bar;
    }

    public Bar RequiredProperty
    {
        get { return this.bar; }
    }

    public void Baz()
    {
        // this.bar is now GUARANTEED to be initialized,
        // so no checks are required
    }
}

Notice that the constructor Guard Clause (throwing an ArgumentNullException) effectively protects the invariants of the class, which is further strengthened by the readonly keyword.

With the dependency part of the class' invariants, you no long have any temporal coupling and you can now implement all members without worrying whether the dependency has been assigned or not.

like image 25
Mark Seemann Avatar answered Sep 18 '22 10:09

Mark Seemann