我一直在使用.NET 4以有限的方式使用可选参数。我最近想过如何实现可选参数以及我遇到的事情。
采用以下示例:
public interface ITest
{
void Go(string val = "Interface");
}
实现这一点的唯一要求是实现签名void Go (string val)
的最大形式,实际上我们不需要实现可选参数,因为编译器负责该连接(尽管使用选项)直接使用具体类时,可选参数不可用。
有了这个说法,为了在两个地方提供功能,并且在实现中可以发现它,可以在接口和实现中实现可选声明。事实上,生产力工具ReSharper在实现接口时会自动将此可选声明拉到具体类型。这似乎是合乎逻辑的事情。然而...
阻止我们在具体类型和界面中使用不同的值是什么?这引发了我今天早上的警钟,好像有人进入更改该值,并忘记将其保留在覆盖/接口的继承之下,根据您访问对象的方式,行为将完全不同。调试可能非常令人沮丧。
试试这个LINQpad脚本:
void Main()
{
IA iface = new A();
A cls = new A();
iface.Go();
cls.Go();
}
interface IA
{
void Go(string val = "Interface");
}
class A : IA
{
public void Go(string val = "Class") { val.Dump(); }
}
输出将是:
Interface
Class
这让我想到了我的实际问题:
我们可以采用什么(如果有的话)保护这一点,而不会失去使用具体类中的可选参数变体的能力,因此编码器可以发现/读取它?
以前有人遇到过这个问题吗?你是怎么解决的?是否有任何最佳实践可以帮助防止此问题在多开发人员大规模代码库中变得普遍?
答案 0 :(得分:3)
没有什么可以阻止你这样做。使用可选参数将值烘焙到方法调用中。正如您所看到的那样,调用IA.Go()
和A.Go()
会为您提供不同的值,因为它们已编译为IA.Go("Interface")
和A.Go("Class")
。
围绕它的方式(意味着仅在实现中提供“default”参数)是使用重载而不是可选参数:
interface IA
{
void Go();
void Go(string val);
}
public class A : IA
{
public void Go()
{
Go("Class");
}
public void Go(string val) { val.Dump(); }
}
其他一些选择:
答案 1 :(得分:1)
我认为这是C#的本质,你必须忍受它。看下面的例子。 没有可选参数,即行为是否相同,具体取决于您访问对象的方式。
class Program
{
static void Main(string[] args)
{
IA iface = new A();
A cls = new A();
iface.Test();
cls.Test();
Console.ReadKey();
}
}
interface IA
{
void Test();
}
class A : IA
{
public void Test()
{
Console.WriteLine("Class");
}
void IA.Test()
{
Console.WriteLine("Interface");
}
}