在挖掘我公司的代码库时,我发现了令我惊讶的东西: 只有可选参数不同的功能对,这里有一个例子:
public static List<AvailableDay> Find(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour)
public static List<AvailableDay> Find(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour, int maxDaysResultCout = 1)
我发现很奇怪的是,编译器对它们很满意。
对此有何解释?我错过了什么吗?
答案 0 :(得分:25)
这是完全有效的代码。但是,在您的情况下,从不使用可选参数,因为当使用六个参数调用方法时,编译器总是更喜欢第一个重载。
当面对需要编译器填写可选参数值的方法和不使用编译器的方法之间进行选择时,如果这些方法不是&#34;绑定&#34; (即正常参数转换尚未确定获胜者),重载决策将选择调用者明确指定所有参数的那个。
可能存在编译器在第二个上选择第一个重载的情况,因为隐藏了更具体的方法。这是一个有点人为的例子:
interface Foo {
void Bar(int a, int b = 1);
}
class FooImpl : Foo {
public void Bar(int a, int b) {
Console.WriteLine("bar/2");
}
public void Bar(int a) {
Console.WriteLine("bar/1");
}
}
如果你这样做
Foo f1 = new FooImpl();
f1.Bar(1); // Here, Bar(int a, int b = 1) is the only choice
bar/2
会被打印出来,但是如果你这样做了
FooImpl f2 = new FooImpl();
f2.Bar(1); // Here Bar(int a) of the implementation wins
bar/1
被打印(demo)。
答案 1 :(得分:7)
可选参数,只是C#中的语法糖。
如果您使用以下方法使用可选参数:
public void DeleteFiles(string extension = "*.*")
此方法的真正签名是
public void DeleteFiles(string extension)
当您使用此方法时,编译器会在此处执行此操作:
obj.DeleteFiles();
当编译器正在完成她的工作时,他接到没有参数的 DeleteFiles ,并且他试图找到它,但他不能这样他会尝试查找和重载使用可选的参数,这次他找到了, DeleteFile(string),现在他就可以了。
实际上编译的代码将是:
var extension = "*.*";
obj.DeleteFiles(extension);
因此,如果您尝试执行此代码:
public class A
{
public void DeleteFiles(string extension = "*.*")
{
}
public void DeleteFiles(string extension2)
{
}
}
编译器将给出以下错误消息:
错误CS0111:输入&#39; A&#39;已经定义了一个名为&#39; DeleteFiles&#39;使用相同的参数类型
现在我们有了这个课程
public class A
{
public void DeleteFiles(string folderPath)
{
}
public void DeleteFiles(string folderPath, string extension = "*.*")
{
}
}
这种情况下的真实代码是
public class A
{
public void DeleteFiles(string folderPath)
{
}
public void DeleteFiles(string folderPath, string extension)
{
}
}
然后你有这个代码:
aInstance.DeleteFiles("path")
编译器将查看是否存在接收一个参数的 DeleteFiles 方法。他会找到的。
因此,在这种情况下,将永远不会使用可选参数功能,因为有一个完美的方法签名,使编译器永远不会尝试查找使用可选参数的其他签名。