[英]How can I wrap a method with optional parameters in C#?
I have the following C# class (simplified here): 我有以下C#类(在此简化):
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"
. 如您所见,我有一个Assertions.Assert()
方法,带有可选参数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. 当我围绕该方法编写包装器时,我希望包装器具有默认的参数string message
,但是我想避免重复默认值( "Assertion failed"
),因为这违反了DRY原理:如果我想要要将消息"Assertion failed"
更改为"I crashed"
,我将不得不在许多地方更改该默认值。
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. 另一个选择是不使用可选参数,并为每个方法提供两个版本,但这会很快变得麻烦。
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): 如果您不想重复自己的话,我的建议是引入一个特殊值(以模仿Type.Missing
是什么):
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 ). 这还有另一个(IMO大的)优势:如果您更改错误消息 (或将其本地化 ),则不必更改所有代码(现有的编译库将被更新 )。 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: 将被转换(和编译,即使您使用const
字段)为:
Assertions.Assert(value > 0, "Assertion failed");
So, even if you'll change your default message, compiled assemblies won't get updated. 因此,即使您更改默认消息,编译后的程序集也不会得到更新。
I prefer to use null
as the default value for optional arguments. 我更喜欢将null
作为可选参数的默认值。
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);
}
}
The default value needs to be specified on the first method called (ie 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. Type.Missing
是一个特殊的值,在COM互操作中具有含义。 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. 在基本方法上使用OptionalAttibute ,并在覆盖的方法上指定默认值。
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. 将默认值声明为in,并应用与默认值相同的常量。
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. 在包装器中将null用作默认值,并对对基本方法的两个替代调用进行编码。
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; } }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.