Optional and Named Arguments in C# 4

After focusing on some of the .NET framework enhancements, I thought I’d turn my attention to two of my most anticipated new features coming with C# 4 – Optional and Named Arguments.  These two features provide benefits I haven’t seen mentioned in most of the announcements…

One annoyance has always been the amount of code duplication required in C# when it comes to construction and method overloading.  For example, say we have a class named Test which can take up to four strings as arguments in its constructor, we often would up writing code like this:

class Test
{
    public Test() : this("1","2","3","4")
    { }

    public Test(string one) : this(one, "2", "3", "4")
    { }

    public Test(string one, string two) : this(one, two, "3", "4")
    { }

    public Test(string one, string two, string three) : this(one, two, three, "4")
    { }

    public Test(string one, string two, string three, string four)
    {
        this.one = one;
        this.two = two;
        this.three = three;
        this.four = four;
    }

Basically, in order to provide the ability to allow up to four arguments, we end up writing four versions of our constructor, and use constructor chaining to push them all together.

This has quite a few problems.  First, it’s a lot of code, which means more maintenance, and more chance for introducing bugs.  It’s very easy for a developer, later, to accidentally add logic to the wrong constructor (probably the one they are using at the time), so the logic only happens some of the time, but not all of the time.  Changing “defaults” can be problematic, since you have to change them correctly in multiple locations, or be very careful in how you chain your constructors.

C# 4 addresses this by allowing us to specify a single constructor, with default parameter values.  This makes using the parameters optional, with a single constructor:

class Test
{
    public Test(string one = "1", string two = "2", string three = "3", string four = "4")
    {
        this.one = one;
        this.two = two;
        this.three = three;
        this.four = four;
    }

Now, we can just implement a single constructor, and more importantly, just maintain a single constructor.  We actually get even more benefits than just a single implementation, especially from the point of view of the user of our class.  When we go to use this class, not only do we have the option of specifying one to four parameters, but Visual Studio’s intellisense also shows the user of our class all of the default values:

valuesFromUser

This, to me, is another huge advantage in terms of usability.  We now, in addition to providing our users a lot of flexibility, can convey information about what default will be chosen if the user does not specify a default value, without them needing to consult documentation.  This can give the user a very clear idea of what is being used to initialize the class, and make them intuitively more aware of how to correctly use your type.

Another new feature in C# 4 is named arguments.  Named arguments add power and flexibility when combined with optional arguments by allowing us to specify, individually, in any order, any of the arguments.  For example, if we want to call the constructor for test above, but only specify an argument for the third argument, we can do it by name:

Test test = new Test(three: "Third argument");

This provides a huge amount of flexibility.  Now we can specify any number of optional arguments, directly in our constructor, in any order.  For example, the following are all valid:

Test first = new Test("One");
Test second = new Test(two: "Two");
Test third = new Test(three: "Three", one: "one");
Test fourth = new Test("One", four: "Four");

This is huge in terms of flexibility.  Our single constructor provides the user with a huge amount of flexibility in calling, without implementing many versions of our constructor.  In fact, this provides the same effect as having ten overloaded constructors, which, in C# 3 and earlier, would not have even been possible since the parameters all have the same type.

C# 3.0 provided us with Object Initializers, which, I’ll grant, provided most (but not all) of this functionality for construction.  Using an object initializer, we could have provided the first and last constructor above, and placed the other arguments into the initialization block.  This would have made the usage look something like:

Test test = new Test
    {
        One = "One",
        Three = "Three"
    };

This, at first, seems like it accomplishes the same thing, but there are two distinct differences here. 

First, the properties or fields named “One” and “Three” are set after the object is constructed.  This can, potentially, lead to issues, especially if the “real” values are needed during the construction of the object.

Second, object initializers only work if the properties or fields you are setting are visible to you, which usually means exposing a public property.  Often, it is useful to provide an object values for construction that are not necessary as part of their public API.  The new C# 4 construction methods are superior at handling both of these situations.

In addition to this, named and optional arguments work in method calls, indexers, and delegates.  For example, we can add a method to our Test class like so:

partial class Test
{
    public void Print(bool printOne = true, bool printTwo = true, bool printThree = true, bool printFour = true)
    {
        if (printOne)
        {
            // ...

Calling this is the same as with the constructor examples:

testInstance.Print(printThree: false, printFour: false);

Again, we get all of the same usability, flexibility, and intellisense features on this method, without having to make multiple overloads of the method in our class.  This means less code duplication, and much better maintainability.

About Reed
Reed Copsey, Jr. - http://www.reedcopsey.com - http://twitter.com/ReedCopsey

Comments

One Response to “Optional and Named Arguments in C# 4”

Trackbacks

Check out what others are saying about this post...
  1. [...] my last post, I discussed one of my favorite new features in C# – Optional and Named Arguments.  Although [...]



Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!