Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中包装带有可选参数的方法?_C#_Default Value_Optional Parameters - Fatal编程技术网

如何在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”?我要找的东西是:

我有以下C类(此处简化):

如您所见,我有一个带有可选参数
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;
        }
    }
    
  • 在包装器中使用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;
        }
    }
    

  • 需要在调用的第一个方法(即包装器)上指定默认值,因为这是将值应用于参数的地方<代码>类型。缺少是一个在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;
        }
    }
    
  • 在包装器中使用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;
        }
    }
    

  • 一个
    const
    字符串可能是@SimonWhitehead这是个好主意,我不知道为什么我没有想到。一个
    const
    字符串也许@SimonWhitehead这是个好主意,我不知道为什么我没有想到。请注意,您可以使用coalesce(
    )操作符简化此操作,即
    消息??“断言失败”
    。请注意,您可以使用coalesce(
    ??
    )操作符简化此操作,即
    消息??“断言失败”
    。OptionalAttribute将如何更改C#行为?在这里,它是相当无用的。第三种方法与在内部类中执行相同(只是更加冗长)。第二个很好,由于本地化的原因,我不会对字符串使用它,但它可以工作。
    OptionalAttribute
    只允许您指定可选参数,而无需指定默认值。它在功能上等同于
    Type parameter=default(Type)
    。您完全正确,由于本地化,使用默认字符串通常是一个坏主意,除非它是资源文件中的查找值。关于[可选],是的,这就是为什么在该示例中我认为它没有用的原因!我同意第二条评论(即使……老实说……我也不喜欢本地化的异常消息,因为大多数时候它只是从客户那里得到的信息……+1表示方法2。方法1在我的例子中不适用,因为我在一个核心方法周围有很多包装器,所以使用我仍然需要为每个包装器提供默认值,此外,核心方法可以在没有包装器的情况下调用,因此它无论如何都应该有正确的默认值。另外,为什么要将包装器分为子类?在我的问题中,核心方法和包装器只是静态方法,不涉及继承?在这里,它是相当无用的。第三种方法与在内部类中执行相同(只是更加冗长)。第二个很好,由于本地化的原因,我不会对字符串使用它,但它可以工作。
    OptionalAttribute
    只允许您指定可选参数,而无需指定默认值。它在功能上等同于
    Type parameter=default