C# 4.0 Optional Parameters

One of the new language features coming in C# 4.0 is Optional Parameters. In large part, this is due to Microsoft's plan of co-evolution with C# and VB.NET since VB.NET has had this feature for a while.  Personally, I'm still somewhat undecided about this feature and there has been much written about method overloads versus optional parameters. For example, Considerations in Overloading Procedures.  Ultimately, I do think there will be some scenarios where this will be useful to make code more concise.

Consider a standard scenario with method overloading or constructor chaining.  In C# we'd have several methods with different signatures where, in effect, we're really just after default values. Let's take the scenario where we've got a little helper class to send emails in our application. In some cases we want to CC the administrator to troubleshoot issues; in some cases we want rich HTML emails rather than plain text. We might set up our methods like this:

public void SendMail(string toAddress, string bodyText)
{
    this.SendMail(toAddress, bodyText, true);
}
 
public void SendMail(string toAddress, string bodyText, bool ccAdministrator)
{
    this.SendMail(toAddress, bodyText, ccAdministrator, false);
}
 
public void SendMail(string toAddress, string bodyText, bool ccAdministrator, bool isBodyHtml)
{
    // Full implementation here
}

This is pretty standard method overloading and we essentially are setting default values (true for CC the Admin, and false for HTML emails). With C# 4.0 we can now make the code more concise by only having to implement 1 method:

public void SendMail(string toAddress, string bodyText, bool ccAdministrator = true, bool isBodyHtml = false)
{
    // Full implementation here
}

However, you do have to take into account your scenario.  If you have a situation where you actually need to know if the consuming code provided a value then this isn't a good option because if "true" comes in for the 3rd parameter, you don't know if the consuming code actually set this explicitly or if it was simply the result of the default value.  But in typical scenarios like this, it's not a big deal.  Cracking open Reflector and looking at the IL that the C# compiler is generating:

.method public hidebysig instance void SendMail(string toAddress, string bodyText, [opt] bool ccAdministrator, [opt] bool isBodyHtml) cil managed
{
    .param [3] = bool(true)
    .param [4] = bool(false)
    .maxstack 8
    L_0000: nop
    L_0001: ret
}

Which Reflectors translates to a C# equivalent of:

public void SendMail(string toAddress, string bodyText, [Optional, DefaultParameterValue(true)] bool ccAdministrator, [Optional, DefaultParameterValue(false)] bool isBodyHtml)
{
}

So if consuming code is written using the least specified "overload" like this:

email.SendMail("bob@foo.com", "Hello World");

The IL that the C# compiler will generate will actually be the equivalent of this:

email.SendMail("bob@foo.com", "Hello World", true, false);

What's more interesting is that, unlike traditional method overloading, you have the ability to omit only the 3rd parameter in conjunction with the new Named Parameters language feature and write your code like this:

email.SendMail("bob@foo.com", "Hello World", isBodyHtml: true);

This will allow consuming code to only pass 3 arguments for succinctness but still invoke the appropriate overload since the IL generated in that instance will be equivalent to this:

email.SendMail("bob@foo.com", "Hello World", true, true);

Overall, it's by no means an earth shattering feature that is being added to the language in stand-alone scenarios (though it will be have a much bigger impact in COM Interop).  Used in the correct scenarios, it can improve your code.

Tweet Post Share Update Email RSS