我有以下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);
}
}
如您所见,我的方法Assertions.Assert()
带有可选参数string message = "Assertion failed"
。
当我围绕该方法编写包装器时,我希望包装器具有默认参数string message
,但我想避免重复默认值("Assertion failed"
),因为这违反了DRY原则:如果我想将消息"Assertion failed"
更改为"I crashed"
,我将不得不在许多地方更改该默认值。
如何传递可选参数的“缺失”?我正在寻找类似的东西:
public static void NotNull(object o, string message = Type.Missing) {
Assert(!Object.ReferenceEquals(o, null), message);
}
另一个选择是不使用可选参数并为每个方法提供两个版本,但这很快就会变得很麻烦。
答案 0 :(得分:3)
可选参数在编译时解析,并且不会替换特殊值,因此您没有很多选项。
我的建议,如果你不想重复自己,就是引入一个特殊的价值(模仿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);
}
}
这还有另一个(IMO大)优势:如果您更改了错误消息(或者将其本地化),则无需更改所有代码(现有的编译库将 更新 )。不要忘记,在您的原始代码中,这样的调用:
Assertions.Assert(value > 0);
将被翻译(并编译,即使您使用const
字段):
Assertions.Assert(value > 0, "Assertion failed");
因此,即使您将更改默认消息,编译的程序集也不会更新。
答案 1 :(得分:1)
我更喜欢使用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);
}
}
答案 2 :(得分:0)
需要在调用的第一个方法(即包装器)上指定默认值,因为这是将值应用于参数的位置。 Type.Missing
是一个特殊值,在COM互操作中有意义。以下是您可以尝试的一些可能符合您需求的选项。
在基本方法上使用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;
}
}
将默认值声明为常量,并将相同的常量应用为默认值。
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;
}
}
在包装器中使用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;
}
}