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 cannot 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 its 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 by actually splitting the method into two. It’s the same as with one-liners – less code is not necessarily better.
CodeProject