C# 可选参数和方法重载同时使用造成的困惑
C# 中可选参数是一个很方便的功能,但是在和重载同时使用时发现了一个比较困惑的地方。
比如下面例子中的前两个方法,第二个方法在可选参数不传的情况下,其调用的方式是和第一个方法一样的。
本以为编译器在编译时会报错,但实际并非如此。
在下面的例子中定义了 7 个方法定义,只有两种认为是参数类型重复了。
也就是说 方法定义是否重复的认定是不管参数是不是可选参数,也不管方法的返回值类型是否相同,只按照参数的顺序和类型来判定。
OverloadTest.cs
csharp
class OverloadTest
{
public void Method1(string arg1)
{
Console.WriteLine("Method1 - 1");
}
public void Method1(string arg1, string arg2 = "")
{
Console.WriteLine("Method1 - 2");
}
public void Method1(string arg1, string arg2 = "", string arg3 = "")
{
Console.WriteLine("Method1 - 3");
}
public void Method1(string arg1, string arg2 = "", int arg3 = 0)
{
Console.WriteLine("Method1 - 4");
}
public void Method1(string arg1, int arg3 = 0, string arg2 = "")
{
Console.WriteLine("Method1 - 5");
}
//// 编译报错:类型“OverloadTest”已定义了一个名为“Method1”的具有相同参数类型的成员
//public string Method1(string arg1)
//{
// return arg1;
//}
//// 编译报错:类型“OverloadTest”已定义了一个名为“Method1”的具有相同参数类型的成员
//public void Method1(string arg1, int arg2 = 0, string arg3 = "")
//{
//}
}
下面是这几个方法的调用,比较有意思的是最后编译出错的两个。
本意是调用打印 Method1 - 4 和 Method1 - 5 的两个方法的,但是在使用 命名实参 进行传递时编译报错了。
csharp
var test = new OverloadTest();
test.Method1("1"); // Method1 - 1
test.Method1("1", "2"); // Method1 - 2
test.Method1("1", "2", "3"); // Method1 - 3
test.Method1("1", "2", 3); // Method1 - 4
test.Method1("1", 2, "3"); // Method1 - 5
test.Method1("1", arg2: "2"); // Method1 - 2(其实对方法 2 3 4 5 都符合)
test.Method1("1", arg2: "2", arg3: "3"); // Method1 - 3
// 编译报错:以下方法或属性之间的调用具有二义性:“OverloadTest.Method1(string, string, int)”和“OverloadTest.Method1(string, int, string)”
//test.Method1("1", arg2: "2", arg3: 3);
// 编译报错:以下方法或属性之间的调用具有二义性:“OverloadTest.Method1(string, string, int)”和“OverloadTest.Method1(string, int, string)”
//test.Method1("1", arg3: 2, arg2: "3");
说来这个也许就是 java 方法为什么没有可选参数的原因,可能会导致方法调用时的二义性。
又想到两种通过 命名实参 方式的调用:
csharp
test.Method1("1", arg3: "3"); // Method1 - 3(仅符合方法 3 的定义)
// 编译报错:以下方法或属性之间的调用具有二义性:“OverloadTest.Method1(string, string, int)”和“OverloadTest.Method1(string, int, string)”
//test.Method1("1", arg3: 3); // Method1 - 3
总的来说感觉如果带可选参数的重载多了之后,调用感觉很混乱,建议不要两种方法同时使用,如果同时使用,应避免出现方法签名覆盖的情况出现。