0

Let's say I have a class like this:

public class MyClass
{
    public string A { get; }
    public string B { get; }
    public string C { get; }

    public MyClass(string a, string b, string c)
    {
        this.A = a ?? throw new ArgumentNullException(nameof(a));
        this.B = b ?? throw new ArgumentNullException(nameof(b));
        this.C = c ?? throw new ArgumentNullException(nameof(c));
    }
}

and some methods somewhere using an instance of it:

public void DoMagic(MyClass myClass)
{
    if(myClass == null) throw new ArgumentNullException(nameof(myClass));

    // do stuff using myClass.A, myClass.B, myClass.C
}

At this point, we know for a fact that in the method body, neither myClass nor any of its properties can be null, and thus we can use them securely.

But this will break if at any point the spec for the class changes and all of a sudden one of its property becomes optional.

What is to be done in this case ? Should I rely on the properties being validated inside the class, or should I put guard clauses for A, B and C everywhere inide methods using them ? Wouldn't this bloat the code too much ?

Is there a general recommended strategy in this case ? Or several depending on some context variations ?

4
  • What is an example of a guard clause?
    – paparazzo
    Commented Mar 24, 2018 at 12:09
  • @paparazzo Something like if(myClass.C == null) throw ... Commented Mar 24, 2018 at 12:59
  • 1
    Stuff like this is why I wish CodeContracts was still being developed.
    – Andy
    Commented Sep 27, 2018 at 23:57
  • @Andy I couldn't agree more. Commented Sep 28, 2018 at 1:31

1 Answer 1

1

Why would a property becoming optional break this approach? If it's optional, it's reasonable to assume it'll have a default value and thus still won't be null, eg:

public class MyClass
{
    public const string DefaultC = "";

    public string A { get; }
    public string B { get; }
    public string C { get; } = DefaultC;

    public MyClass(string a, string b, string c = DefaultC)
    {
        A = a ?? throw new ArgumentNullException(nameof(a));
        B = b ?? throw new ArgumentNullException(nameof(b));
        if (c != null) C = c;
        // or if you still want to throw on a null c, stay with,
        // C = c ?? throw new ArgumentNullException(nameof(c)); 
    }
}

So it can still be used securely.

4
  • Of course. I was wondering about the case where it would be made optional without any default value. But I guess it's up to us to prevent this from happening. I guess that's that simple :) Commented Mar 23, 2018 at 9:32
  • (1) public string C { get; } = DefaultC; (2) string c = DefaultC (3) if (c != null) C = c; This makes no sense. (3) tests for null, but (2) ensures that the value can never be null (it will be DefaultC if null was passed by the external caller). Therefore, (3) will always evaluate to true and will always set C. Which means that the default value in (1) and the if-check in (3) are both unnecessary.
    – Flater
    Commented Mar 26, 2018 at 9:22
  • 1
    @Flater, not so, unfortunately. Please see here for what happens when null is passed and we remove that if
    – David Arno
    Commented Mar 26, 2018 at 9:29
  • The compiler isn't required to abide by default values, which is partly why they should be avoided.
    – Zymus
    Commented Mar 31, 2018 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.