C# optional parameter visibility

Optional parameters in C# allow you to specify a default value of a method parameter. This lets you have several overloads of a method while still having a single method signature and implementation, which is easier to maintain. However, when you need to create an overload of a method, adding an optional parameter might not always be the right solution.

Consider the following simplified version of code that I found in the codebase I currently work on:

public class Client
{
    ...

    public void CloseAccount(Guid accountId, bool shouldCloseClient = true)
    {
        this.Accounts.Single(x => x.Id == accountId).Close();

        if(this.Accounts.All(x => x.State == AccountStates.Closed) && shouldCloseClient)
            this.Close();
    }

    ...
}

The scenario here is simple. Client can have multiple accounts and they might be closed at some points in time. Client class is the root of client aggregate, so closing the account must be done using the method demonstrated above. If we are closing the last account, the client should be closed too.

The method is called from outside by passing an accountId only. However, if this method is called from the inside of the class, a false is passed as shouldCloseClient parameter value. In this case, it is to stop recursion, because Client.CloseAccount calls Client.Close and vice versa. The actual code is more complex than what is demonstrated here, but I hope it can help illustrate the problem of abusing optional parameters.

The problem here is that shouldCloseClient parameter was meant to only be used from the inside of the Client class. That sounds like a case for applying private or protected access modifiers, but optional parameters can not have them.

That’s why it is better to actually split the method into two, in the usual old school style:

public class Client
{
    ...

    public void CloseAccount(Guid accountId)
    {
        CloseAccountWithoutClosingClient(accountId);

        if(this.Accounts.All(x => x.State == AccountStates.Closed))
            this.Close();
    }

    private void CloseAccountWithoutClosingClient(Guid accountId)
    {
        this.Accounts.Single(x => x.Id == accountId).Close();
    }

    ...
}

By introducing a new method CloseAccountWithoutClosingClient, we are able to change it’s access modifier to private. As a bonus, we also get a chance to pick a more expressive name to distinguish it from the other method.

Every time you add an optional parameter to a method, consider how it will be used from outside and inside of the class and if you can benefit of actually splitting the method into two. It’s the same as with one-liners – less code is not necessarily better.

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