Reputation: 3244
I have the following C# class (simplified here):
internal static class Assertions {
public static void Assert(bool condition, string message = "Assertion failed") {
if (!condition) { throw new System.Exception(message); }
}
public static void NotNull(object o, string message = "Assertion failed") {
Assert(!Object.ReferenceEquals(o, null), message);
}
public static void EtCaetera(..., string message = "Assertion failed") {
Assert(..., message);
}
}
As you can see, I have a method Assertions.Assert()
with an optional parameter string message = "Assertion failed"
.
When I write a wrapper around that method, I'd like the wrapper to have a default parameter string message
, but I'd like to avoid repeating the default value ("Assertion failed"
) because that violates the DRY principle: if I want to change the message "Assertion failed"
to "I crashed"
, I'll have to change that default value in many places.
How can I pass-through the "missingness" of the optional parameter? I'm looking for something like:
public static void NotNull(object o, string message = Type.Missing) {
Assert(!Object.ReferenceEquals(o, null), message);
}
ANother option would be not to use optional parameters and provide two versions of each method, but that would quickly get cumbersome.
Upvotes: 2
Views: 915
Reputation: 67090
Optional parameters are resolved at compile time and they're not replaced for special values so you don't have many options here.
My suggestion, if you don't want to repeat yourself, is to introduce a special value (to mimic what Type.Missing
is):
internal static class Assertions {
public static void Assert(bool condition, string message = null) {
if (!condition) {
throw new System.Exception(message ?? "Assertion failed");
}
}
}
internal static class Wrapper {
public static void Assert(bool condition, string message = null) {
Assertions.Assert(condition, message);
}
}
This has another (IMO big) advantage: if you change your error message (or you'll localize it) you won't have to change all your code (and existing compiled libraries will be updated). Don't forget that, in your original code, a call like this:
Assertions.Assert(value > 0);
Will be translated (and compiled, even if you use a const
field) to:
Assertions.Assert(value > 0, "Assertion failed");
So, even if you'll change your default message, compiled assemblies won't get updated.
Upvotes: 3
Reputation: 126
The default value needs to be specified on the first method called (i.e. your wrapper) as this is where the value is applied to the parameter. Type.Missing
is a special value that has meaning in COM interop. Here are some options you could try that may suit your needs.
Use the OptionalAttibute on the base method and specify the default value on the overridden method.
class Class2 : Class1
{
public override string MethodWithOptParams(string message = "default message")
{
return base.MethodWithOptParams(message);
}
}
class Class1
{
public virtual string MethodWithOptParams([Optional]string message)
{
return message;
}
}
Declare your default values as constants in and apply the same constant as the default value.
class Class2 : Class1
{
public override string MethodWithOptParams(string message = DefaultMessage)
{
return base.MethodWithOptParams(message);
}
}
class Class1
{
protected const string DefaultMessage = "default message";
public virtual string MethodWithOptParams(string message = DefaultMessage)
{
return message;
}
}
Use null as the default value in your wrapper and code the two alternative calls to the base method.
class Class2 : Class1
{
public override string MethodWithOptParams(string message = null)
{
if (message == null)
{
return base.MethodWithOptParams();
}
else
{
return base.MethodWithOptParams(message);
}
}
}
class Class1
{
public virtual string MethodWithOptParams(string message = "default message")
{
return message;
}
}
Upvotes: 0
Reputation: 86729
I prefer to use null
as the default value for optional arguments.
internal static class Assertions {
private const string DefaultMessage = "Assertion failed";
public static void Assert(bool condition, string message = null) {
message = message ?? DefaultMessage;
if (!condition) { throw new System.Exception(message); }
}
public static void NotNull(object o, string message = null) {
message = message ?? DefaultMessage;
Assert(!Object.ReferenceEquals(o, null), message);
}
public static void EtCaetera(..., string message = null) {
message = message ?? DefaultMessage;
Assert(..., message);
}
}
Upvotes: 1