Neat uses of Optional Arguments in C#

I have been using .NET 4 for a while now but I have to admit I never thought well of optional arguments. My impressions gravitated between

  1. method overloading for lazy people
  2. hiding hideously designed APIS (Office COM Automation, I am looking at you!)

And so I have not used the feature extensively. But during the last week I have found a couple of usages that I can label as “useful”. Let me tell you about them:

Replace property initializers with descriptive constructors

Property initializers are cool. A bit verbose, due to curly bracing, but cool. Have properties with sensible names and you have a very descriptive and flexible way of creating objects. Perhaps too flexible. No one enforces you a minimum set (unless places in a constructor) and it is easy to forget setting a property.

Problem is, that if you have a long parameter list it is really easy to loose overview and what is which. Furthermore, have more than two properties with the same type together and you are likely to make mistakes (is latitude the first one, or is it longitude?).

Can’t I have my cake and eat it too? Yes, but please, share.

Imagine a class that has loads of properties (all cohesive, before you ask Winking smile):

public class IHaveQuiteAFewProperties
{
    public int I1 { get; set; }
    public int I2 { get; set; }
    public string S { get; set; }
    public decimal D1 { get; set; }
    public decimal D2 { get; set; }

    public IHaveQuiteAFewProperties() { }
}

Use very expressive property initializers and forget something:

var subject = new IHaveQuiteAFewProperties
{
    I1 = 1, I2 = 2,
    S = "something",
    // snaps! I forgot to set D1 to -3.5m,
    D2 = -4.3m
};

But, with a constructor that sets all properties…

public IHaveQuiteAFewProperties(int i1, int i2, string s, decimal d1, decimal d2)
{
    I1 = i1;
    I2 = i2;
    S = s;
    D1 = d1;
    D2 = d2;
}

…one can happily create an object, forget nothing and be expressive about what every argument means:

var subject = new IHaveQuiteAFewProperties(
    i1: 1, i2: 2,
    s: "something",
    d1: -3.5m, d2: -4.3m);

Specify just the argument that changes

Another case I recently found where they can dramatically improve readability is, not surprisingly, when one wants to override the default value Smile with tongue out

Let’s imagine we have a simple object that contains some collections:

public class CollectionOfCollections
{
    public string[] CollectionOne { get; set; }
    public string[] CollectionTwo { get; set; }
    public string[] CollectionThree { get; set; }
    public string[] CollectionFour { get; set; }
}

While testing a piece of code that creates an instance of this CollectionOfCollections in a way that only one of the collections is populated with a certain number of elements, while the other collections are to remain empty. One way of achieving it is asserting on each of the properties. I think that with very little work we can do much better:

[Test]
public void WhenBuildingComplexCollectionOfCollections_OnlyOneOfTheCollectionsIsPopulated()
{
    var subject = new CollectionBuilder();
    CollectionOfCollections result = subject.BuildWithComplexLogic();
    Assert.That(result, withMemberCount(two: 2));
}

What is inside this withMemberCount() method?
A simple default nullable argument that gets translated either into a collection length constraint or to an empty collection constraint for each one of the collections.

private static Constraint withMemberCount(uint? one = null, uint? two = null, uint? three = null, uint? four = null)
{
    return new LambdaPropertyConstraint<CollectionOfCollections>(b => b.CollectionOne, lengthOrEmpty(one)) &
        new LambdaPropertyConstraint<CollectionOfCollections>(b => b.CollectionTwo, lengthOrEmpty(two)) &
        new LambdaPropertyConstraint<CollectionOfCollections>(b => b.CollectionThree, lengthOrEmpty(three)) &
        new LambdaPropertyConstraint<CollectionOfCollections>(b => b.CollectionFour, lengthOrEmpty(four));
}

private static Constraint lengthOrEmpty(uint? length)
{
    return length.HasValue ?
        Has.Length.EqualTo(length.Value) :
        (Constraint)Is.Empty;
}

Neat is not enough. One starts to reap the benefits really soon when several tests are written and each one asserts a different count on different collections.

NOTE: LambdaPropertyConstraint<> is a typed counterpart to the out-of-the-box in NUnit’s PropertyConstraint that allows passing further constraints to be applied to the member. It is part of Testing.Commons.NUnit.

Kategorier: Udvikling

Tagged as: , ,

Skriv et svar

Udfyld dine oplysninger nedenfor eller klik på et ikon for at logge ind:

WordPress.com Logo

Du kommenterer med din WordPress.com konto. Log Out / Skift )

Twitter picture

Du kommenterer med din Twitter konto. Log Out / Skift )

Facebook photo

Du kommenterer med din Facebook konto. Log Out / Skift )

Google+ photo

Du kommenterer med din Google+ konto. Log Out / Skift )

Connecting to %s