Optional parameters for interfaces
使用C 4.0——构建接口和实现接口的类。我想在接口中声明一个可选参数,并让它反映在类中。所以,我有以下几点:
1 2 3 4 5 6 7 8 9 | public interface IFoo { void Bar(int i, int j=0); } public class Foo { void Bar(int i, int j=0) { // do stuff } } |
这是编译的,但看起来不太对劲。接口需要有可选参数,否则它在接口方法签名中不能正确反映。
我应该跳过可选参数并只使用可为空的类型吗?或者这是否会按预期工作而没有副作用或后果?
真正奇怪的是,您为接口中的可选参数输入的值实际上会产生差异。我想您必须质疑这个值是接口细节还是实现细节。我本来会说后者的,但事情的表现却和前者相似。例如,以下代码输出1 0 2 5 3 7。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // Output: // 1 0 // 2 5 // 3 7 namespace ScrapCSConsole { using System; interface IMyTest { void MyTestMethod(int notOptional, int optional = 5); } interface IMyOtherTest { void MyTestMethod(int notOptional, int optional = 7); } class MyTest : IMyTest, IMyOtherTest { public void MyTestMethod(int notOptional, int optional = 0) { Console.WriteLine(string.Format("{0} {1}", notOptional, optional)); } } class Program { static void Main(string[] args) { MyTest myTest1 = new MyTest(); myTest1.MyTestMethod(1); IMyTest myTest2 = myTest1; myTest2.MyTestMethod(2); IMyOtherTest myTest3 = myTest1; myTest3.MyTestMethod(3); } } } |
有趣的是,如果您的接口使参数成为可选的,那么实现它的类就不必这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // Optput: // 2 5 namespace ScrapCSConsole { using System; interface IMyTest { void MyTestMethod(int notOptional, int optional = 5); } class MyTest : IMyTest { public void MyTestMethod(int notOptional, int optional) { Console.WriteLine(string.Format("{0} {1}", notOptional, optional)); } } class Program { static void Main(string[] args) { MyTest myTest1 = new MyTest(); // The following line won't compile as it does not pass a required // parameter. //myTest1.MyTestMethod(1); IMyTest myTest2 = myTest1; myTest2.MyTestMethod(2); } } } |
。
然而,似乎是错误的是,如果显式实现接口,那么在类中为可选值提供的值是无意义的。在下面的示例中,如何使用值9?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // Optput: // 2 5 namespace ScrapCSConsole { using System; interface IMyTest { void MyTestMethod(int notOptional, int optional = 5); } class MyTest : IMyTest { void IMyTest.MyTestMethod(int notOptional, int optional = 9) { Console.WriteLine(string.Format("{0} {1}", notOptional, optional)); } } class Program { static void Main(string[] args) { MyTest myTest1 = new MyTest(); // The following line won't compile as MyTest method is not available // without first casting to IMyTest //myTest1.MyTestMethod(1); IMyTest myTest2 = new MyTest(); myTest2.MyTestMethod(2); } } } |
埃里克·利珀特就这个确切的主题写了一个有趣的系列文章:可选的论据角案例
您可以考虑预先可选的参数替代:
1 2 3 4 5 6 7 8 9 10 11 12 | public interface IFoo { void Bar(int i, int j); } public static class FooOptionalExtensions { public static void Bar(this IFoo foo, int i) { foo.Bar(i, 0); } } |
如果您不喜欢新语言功能的外观,则不必使用它。
您不必在实现中使参数成为可选的。您的代码将更加合理:
1 2 3 4 5 6 7 8 9 | public interface IFoo { void Bar(int i, int j = 0); } public class Foo { void Bar(int i, int j) { // do stuff } } |
。
这样,默认值就明确了。实际上,我很确定实现中的默认值不会有任何影响,因为接口为它提供了一个默认值。
像这样的东西怎么样?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public interface IFoo { void Bar(int i, int j); } public static class IFooExtensions { public static void Baz(this IFoo foo, int i, int j = 0) { foo.Bar(i, j); } } public class Foo { void Bar(int i, int j) { /* do stuff */ } } |
号
要考虑的是当使用模拟框架时会发生什么,这些框架基于接口的反射工作。如果在接口上定义了可选参数,则将根据接口中声明的内容传递默认值。一个问题是,没有什么能阻止您在定义上设置不同的可选值。
撇开不谈,这将完全达到你想要达到的目标。