在挖掘我的公司代码库时,我发现了令我惊讶的东西:只有可选参数不同的功能对,这里有一个例子:
public static ListFind(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour) public static List Find(string mailboxCalendarId, string[] typeTrameCles, DateTime dateMin, bool hasPhNonUrgent, bool hasPhUrgence, bool hasPhUrgenceDuJour, int maxDaysResultCout = 1)
我发现非常奇怪的是,编译器对它们很满意.对此有何解释?我错过了什么吗?
这是完全有效的代码.但是,在您的情况下,永远不会使用可选参数,因为当使用六个参数调用方法时,编译器总是更喜欢第一个重载.
来自C#深度:
当面对需要编译器填充可选参数值的方法和不需要填充的方法之间的选择时,如果方法被"绑定"(即正常参数转换尚未确定胜利者),则选择重载决策调用者明确指定了所有参数的那个.
可能存在编译器在第二个上选择第一个重载的情况,因为隐藏了更具体的方法.这是一个有点人为的例子:
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
得到打印(演示).
可选参数只是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:类型"A"已经定义了一个名为"DeleteFiles"的成员,其成员具有相同的参数类型
现在我们有了这门课
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方法.他会找到的.
因此,在这种情况下,永远不会使用可选参数功能,因为有一个完美的方法签名,使编译器永远不会尝试查找使用可选参数的其他签名.