I'm designing an API wrapper with a constructor something like this:
public class Client(string username, string password, int timeout = 60)
The caller looks like this:
class Program
{
private static int? Timeout => GetFromConfig("Timeout");
static void Main(string[] args)
{
Client client = new Client(Username, Password, Timeout);
// do things...
}
}
I would like to use Client's default timeout (60) if Timeout is null.
I know of a few options:
1) Use conditional logic in Main
static void Main(string[] args)
{
if (Timeout == null)
{
Client client = new Client(Username, Password);
}
else
{
Client client = new Client(Username, Password, Timeout);
}
}
I dislike this solution because 1) it's a lot of code, and 2) the code grows exponentially as I add conditional parameters (e.g. if I added int MaxFailedRequests = 5
to Client()'s signature, my if/else block grows to 4 blocks).
2) Handle null values in Client()
public class Client(string username, string password, int? timeout)
{
_timeout = timeout ?? 60;
}
I dislike this solution, because the default value is no longer exposed in the constructor's signature (which acts as excellent/free documentation).
3) Handle null values in Client() with a default value
public class Client(string username, string password, int? timeout = 60)
{
_timeout = timeout ?? 60;
}
I dislike this solution because 1) it's not immediately obvious how null will be handled (requires more documentation), and 2) the default value is duplicated (it would stink if someone modified one but forgot to modify the other).
4) Use null operator and usedefaultparam
keyword in Main
static void Main(string[] args)
{
Client client = new Client(Username, Password, Timeout ?? usedefaultparam);
// ...
}
I like this solution because it's easy to read and grows nicely if I add more optional parameters.
I dislike it because the usedefaultparam
keyword doesn't seem to exist.
Thus my question:
Does something like option 4 exist? If not, is there a nicer, fifth pattern I am not thinking of?
The caller is either supposed to provide a value for the timeout parameter or use the default one that is defined in the Client
class' constructor.
If you want to be able to use the default value that you define in the Client
class in the caller class, you should expose it from the Client
class. You could for example do this using constant:
public class Client
{
public const int DefaultTimeout = 60;
public Client(string username, string password, int timeout = DefaultTimeout)
{
//...
}
}
Caller:
static void Main(string[] args)
{
Client client = new Client(Username, Password, Timeout ?? Client.DefaultTimeout);
// ...
}