C# 4.0: Optional Method Parameters

In this first post on new C# language features I will write about Optional Parameters and Named Parameters for methods.

Past and Present

In the current and previous versions of C#, if you wanted to give users of your API the ability to use a method with a different number of parameters you had to overload a method:

    public void OldFashionedMethod(string stringParam, int intParam)
    {
      Console.WriteLine("OldFashionedMethod(two parameters) - The parameters are: stringParameter[{0}] intParameter[{1}]",
        stringParam, intParam);
    }

    public void OldFashionedMethod(string stringParam)
    {
      int intParam = 8;
      Console.WriteLine("OldFashionedMethod(one parameter) - The parameters are: stringParameter[{0}] intParameter[{1}]",
        stringParam, intParam);
    }

This allows you to call the method in two ways

SomeClass.OldFashionedMethod("TheParameter", 10);
SomeClass.OldFashionedMethod("TheParameter");

You could of course also use this technique

Future

In th enext version of C# you will be able to provide default values for the parameters of a method, in the declaration of that method

    public void OptionalParameterMethod(string stringParam, int intParam = 8)
    {
      Console.WriteLine("The parameters are: stringParameter[{0}] intParameter[{1}]",
        stringParam, intParam);
    }

This also allows you to write similar as above:
This allows you to call the method in two ways

SomeClass.OptionalParameterMethod("TheParameter", 10);
SomeClass.OptionalParameterMethod("TheParameter");

If it looks like a duck …

If we perform the Duck test on this code we will come to the conclusion that although the code looks the same, the behaviour is different so both probably aren’t ducks.

Using Reflector we can look at how the above is resolved by the compiler:

In the case of overloaded method, the compiler generates the expected method calls, one for each overoaded version:

SomeClass.OldFashionedMethod("TheParameter", 10);
SomeClass.OldFashionedMethod("TheParameter");

However, in the case of default parameter values, the compiler generates calls to the single methods and injects the default parameter value when compiling the call making use of the default parameter:

SomeClass.OptionalParameterMethod("TheParameter", 10);
SomeClass.OptionalParameterMethod("TheParameter", 8);

So the default parameter is not substituted in the method itself, like it is done when using overloaded methods, but it is resolved at the call site.

In practice this means that when the writer of the library changes the value of the default parameter, your code calling this library will not use this new value, unless you recompile your code.

So, what isn’t possible?

Optional parameters are only possible at the end of the parameterlist of a method. So, you can not do the following:

public void OptionalParameterMethod(string stringParam = "DefaultValue", int intParam)

From the above code you might wonder why this isn’t possible, but have a look at the folowing method declaration:

public void OptionalParameterMethod(string stringParam = "DefaultValue", string otherStringParam)

Now, how must the compiler resolve following call?

SomeClass.OptionalParameterMethod("TheParameter");

Is the provided parameter a substitute for the default parameter, or is it a value for the last parameter?

Optional parameters can only be compile time constants. This makes the following impossible:

public void DefaultClassParameter(ParameterClass param = new ParameterClass())

The fact that only compile time constants can be used, limits the use of optional parameters to primitive types, enums, or strings.

Usefull or useless

Optional parameters generally generate some of fuss when discussed because most implemetations use the resolve at call site approach which can produce some unexpected results when the library exposing the method evolves and the default value changes. This article provides some guidance

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s