我注意到,如果在接口上将参数指定为可选参数,则使用C#4中的可选参数,您不必在任何实现类上使该参数可选:
public interface MyInterface
{
void TestMethod(bool flag = false);
}
public class MyClass : MyInterface
{
public void TestMethod(bool flag)
{
Console.WriteLine(flag);
}
}
因此:
var obj = new MyClass();
obj.TestMethod(); // compiler error
var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false
有谁知道为什么可选参数设计为这样工作?
一方面,我认为覆盖接口上指定的任何默认值的能力是有用的,但老实说我不确定您是否应该能够在接口上指定默认值,因为这应该是一个实现决策 .
另一方面,这种断开意味着您不能总是交替使用具体类和接口 . 当然,如果在实现上指定了默认值,那么这不是问题,但是如果你将具体类作为接口公开(使用一些IOC框架来注入具体类),那么真的没有具有默认值的点,因为调用者无论如何都必须始终提供它 .
4 回答
更新:This question was the subject of my blog on May 12th 2011. Thanks for the great question!
假设您有一个描述的接口,以及一百个实现它的类 . 然后你决定使其中一个接口的方法的参数之一可选 . 您是否建议正确的做法是让编译器强制开发人员找到该接口方法的每个实现,并使参数也可选?
假设我们这样做了 . 现在假设开发人员没有实现的源代码:
D的作者应该如何使这项工作?您是否需要在您的世界中打电话给B的作者并要求他们向他们发送新版本的B,使该方法具有可选参数?
那不会飞 . 如果两个人打电话给B的作者,并且其中一个人想要默认为真,其中一个人想要它是假的呢?如果B的作者拒绝一起玩怎么办?
也许在那种情况下他们会被要求说:
所提出的特征似乎给程序员增加了许多不便,代表性功率没有相应的增加 . 这个功能的显着优点是什么证明了用户成本的增加?
可选参数仅使用属性标记 . 此属性告诉编译器在调用站点插入该参数的默认值 .
当C#代码被编译为IL而不是JIT时,调用
obj2.TestMethod();
被obj2.TestMethod(false);
替换 .因此,在某种程度上,调用者始终使用可选参数提供默认值 . 这也会对二进制版本控制产生影响:如果更改默认值但不重新编译调用代码,它将继续使用旧的默认值 .
如果接口方法是implemented explicitly,则您无法执行此操作 .
因为默认参数在编译时解析,而不是运行时 . 因此,默认值不属于被调用的对象,而是属于被调用的引用类型 .
可选参数有点像我理解的宏替换 . 从方法的角度来看,它们并不是真正的可选项 . 如果您转换为接口,那么您看到的行为会导致不同的结果 .