使用c#4.0 - 构建一个接口和一个实现接口的类。我想在界面中声明一个可选参数,并让它反映在类中。所以,我有以下内容:
public interface IFoo
{
void Bar(int i, int j=0);
}
public class Foo
{
void Bar(int i, int j=0) { // do stuff }
}
这编译,但看起来不正确。接口需要具有可选参数,否则它在接口方法签名中无法正确反映。
我应该跳过可选参数并只使用可空类型吗?或者这是否会按预期工作而没有副作用或后果?
答案 0 :(得分:57)
真正奇怪的是,您为界面中的可选参数赋予的值实际上有所不同。我想你必须质疑值是接口细节还是实现细节。我会说后者,但事情就像前者一样。例如,以下代码输出1 0 2 5 3 7。
// 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);
}
}
}
有趣的是,如果您的接口使参数成为可选参数,则实现它的类不必执行相同的操作:
// 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?
// 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);
}
}
}
Eric Lippert写了一个关于这个确切主题的有趣系列,名为:Optional argument corner cases
答案 1 :(得分:28)
您可以考虑使用pre-optional-parameters选项:
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);
}
}
如果您不喜欢新语言功能的外观,则不必使用它。
答案 2 :(得分:4)
您不必在实现中将参数设置为可选。你的代码会更有意义:
public interface IFoo
{
void Bar(int i, int j = 0);
}
public class Foo
{
void Bar(int i, int j) { // do stuff }
}
这样,默认值是明确的。事实上,我很确定实现中的默认值没有效果,因为界面为它提供了默认值。
答案 3 :(得分:3)
这样的事情怎么样?
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 */ }
}
答案 4 :(得分:2)
要考虑的是使用Mocking框架时会发生什么,它基于接口的反射而工作。 如果在接口上定义了可选参数,则将根据接口中声明的内容传递默认值。 一个问题是没有什么能阻止你在定义上设置不同的可选值。
答案 5 :(得分:1)
放在一边,这将完全听起来你想要完成的事情。
答案 6 :(得分:0)
我也可以建议:
public interface IFoo
{
void Bar(int i);
void Bar(int i, int j);
}
public class Foo
{
// when "j" has default value zero (0).
void Bar(int i)
{
Bar(i, 0);
}
void Bar(int i, int j) {}
}