如何在C#中包装带有可选参数的方法?
我有以下C类(此处简化): 如您所见,我有一个带有可选参数如何在C#中包装带有可选参数的方法?,c#,default-value,optional-parameters,C#,Default Value,Optional Parameters,我有以下C类(此处简化): 如您所见,我有一个带有可选参数string message=“Assertion failed”的方法Assertions.Assert() 当我围绕该方法编写包装器时,我希望包装器有一个默认参数字符串message,但我希望避免重复默认值(“Assertion failed”),因为这违反了DRY原则:如果我想将消息“Assertion failed”更改为“I crash”,我必须在许多地方更改默认值 如何通过可选参数的“missingness”?我要找的东西是:
string message=“Assertion failed”
的方法Assertions.Assert()
当我围绕该方法编写包装器时,我希望包装器有一个默认参数字符串message
,但我希望避免重复默认值(“Assertion failed”
),因为这违反了DRY原则:如果我想将消息“Assertion failed”
更改为“I crash”
,我必须在许多地方更改默认值
如何通过可选参数的“missingness”?我要找的东西是:
public static void NotNull(object o, string message = Type.Missing) {
Assert(!Object.ReferenceEquals(o, null), message);
}
另一个选择是不使用可选参数,并为每个方法提供两个版本,但这会很快变得很麻烦。可选参数在编译时解析,并且不会替换为特殊值,因此这里没有太多选项 如果您不想重复,我的建议是引入一个特殊值(模仿
Type.Missing
是什么):
这还有另一个好处:如果更改错误消息(或者将其本地化),则无需更改所有代码(并且现有编译库将更新)。不要忘记,在原始代码中,调用如下:
Assertions.Assert(value > 0);
将被翻译(和编译,即使您使用const
字段)以:
因此,即使更改默认消息,编译后的程序集也不会更新。可选参数在编译时解析,并且不会替换为特殊值,因此这里没有太多选项 如果您不想重复,我的建议是引入一个特殊值(模仿
Type.Missing
是什么):
这还有另一个好处:如果更改错误消息(或者将其本地化),则无需更改所有代码(并且现有编译库将更新)。不要忘记,在原始代码中,调用如下:
Assertions.Assert(value > 0);
将被翻译(和编译,即使您使用const
字段)以:
因此,即使更改默认消息,编译的程序集也不会得到更新。我更喜欢使用
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);
}
}
我更喜欢使用
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);
}
}
需要在调用的第一个方法(即包装器)上指定默认值,因为这是将值应用于参数的地方<代码>类型。缺少是一个在COM互操作中有意义的特殊值。以下是一些适合您需要的选项
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;
}
}
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;
}
}
需要在调用的第一个方法(即包装器)上指定默认值,因为这是将值应用于参数的地方<代码>类型。缺少是一个在COM互操作中有意义的特殊值。以下是一些适合您需要的选项
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;
}
}
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;
}
}
一个
const
字符串可能是@SimonWhitehead这是个好主意,我不知道为什么我没有想到。一个const
字符串也许@SimonWhitehead这是个好主意,我不知道为什么我没有想到。请注意,您可以使用coalesce(?
)操作符简化此操作,即消息??“断言失败”
。请注意,您可以使用coalesce(??
)操作符简化此操作,即消息??“断言失败”
。OptionalAttribute将如何更改C#行为?在这里,它是相当无用的。第三种方法与在内部类中执行相同(只是更加冗长)。第二个很好,由于本地化的原因,我不会对字符串使用它,但它可以工作。OptionalAttribute
只允许您指定可选参数,而无需指定默认值。它在功能上等同于Type parameter=default(Type)
。您完全正确,由于本地化,使用默认字符串通常是一个坏主意,除非它是资源文件中的查找值。关于[可选],是的,这就是为什么在该示例中我认为它没有用的原因!我同意第二条评论(即使……老实说……我也不喜欢本地化的异常消息,因为大多数时候它只是从客户那里得到的信息……+1表示方法2。方法1在我的例子中不适用,因为我在一个核心方法周围有很多包装器,所以使用我仍然需要为每个包装器提供默认值,此外,核心方法可以在没有包装器的情况下调用,因此它无论如何都应该有正确的默认值。另外,为什么要将包装器分为子类?在我的问题中,核心方法和包装器只是静态方法,不涉及继承?在这里,它是相当无用的。第三种方法与在内部类中执行相同(只是更加冗长)。第二个很好,由于本地化的原因,我不会对字符串使用它,但它可以工作。OptionalAttribute
只允许您指定可选参数,而无需指定默认值。它在功能上等同于Type parameter=default