Do not throw any exceptions in property Getters (Part 2 - Exception Handling and rules for it)

Do not throw any exceptions in property Getters (Part 2 - Exception Handling and rules for it)

Some teams use a violation of this rule to control the initialization state of the object.

public class Person {
    private string _name;

    public string Name {
        get {
            if (_name == null)
                throw new NotInitializedException (nameof (Name));
            return _name;
        }

        set => _name = value;
    }
}

The getter should always be designed like a safe accessor. It is better to implement an explicit getter method to throw an exception in those scenarios. Imagine that you would like to use code above like this:

string GetName (Person person) {
    return person.Name ?? string.Empty;
}

This code throws an exception whether you tested it for a null value or not.

We had an intensive discussion about this, and my colleagues give me a good example of a violation of this rule. Struct Nullable<> and its property named Value. The description of this struct is: Represents a value type that can be assigned null. From the business point of view, when you declare the type Int as Nullable, null value is the correct business value. That is true and accessing the value directly using the variable name is OK and safe.

Nullable<int> price = new Nullable<int> ();
if (price == null) {
    price = 10;
}

On the other side, trying access value using the Value property is problematic and throws InvalidOperarionException exception:

Nullable<int> price = new Nullable<int> ();
if (price.Value == null) {
    price = 10;
}

Honestly, in my opinion, properties Value and HasValue are only the syntactic sugar on this struct and are designed as the shortcut for testing and accessing the value. Property Value plays a special role and brings only null testing behavior using the private hasValue field:

public T Value {
    get {
        if (!this.hasValue)
            ThrowHelper.ThrowInvalidOperationException_InvalidOperation_NoValue ();
        return this.value;
    }
}

I must say that this struct and its property Value is not exactly the case we are talking about in this section (Do not throw any exceptions in Getters). But the border is very thin.