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 ?

  • What is an example of a guard clause? – paparazzo Mar 24 '18 at 12:09
  • @paparazzo Something like if(myClass.C == null) throw ... – xlecoustillier Mar 24 '18 at 12:59
  • 1
    Stuff like this is why I wish CodeContracts was still being developed. – Andy Sep 27 '18 at 23:57
  • @Andy I couldn't agree more. – xlecoustillier Sep 28 '18 at 1:31
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.

  • 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 :) – xlecoustillier Mar 23 '18 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 Mar 26 '18 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 Mar 26 '18 at 9:29
  • The compiler isn't required to abide by default values, which is partly why they should be avoided. – Zymus Mar 31 '18 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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