关于方法的重载和默认参数的一点小误区
有某类库A里的一个方法:
public static class Test {
public static void CallMethod(string message) {
Console.WriteLine("调用成功:" + message);
}
}
将类库A编译,然后我们在另一个项目B中引用类库A,我们会这样调用:
A.Test.CallMethod(message : "Start");
// 或者这样调用:A.Test.CallMethod("Start");
有某程序员C某天突然想在A.Test.CallMethod方法多传入一个参数,于是C觉得我可以这样修改原有方法:
public static class Test {
public static void CallMethod(string message, int num = 1) {
Console.WriteLine("调用成功:" + message);
}
}
他觉得这样改,在项目B中原来的调用方式是没有错的,于是C改完程序更新完类库,这时,用户说页面出错了,C打开日志一看,System.MissingMethodException: 找不到方法:“void A.Test.CallMethod(string message)”。
为什么会这样呢?其实你反射一下类库A第一个版本和第二个版本,会发现两个程序集的方法签名是不一样的,如下:
// 这是第一个版本:
public static void CallMethod(string message) {
Console.WriteLine("调用成功:" + message + num);
}
// 这是第二个版本(C修改后的版本):
public static void CallMethod(string message, [Optional, DefaultParameterValue(1)] int num) {
Console.WriteLine("调用成功:" + message + num);
}
于是,C有两种解决方式:
一:重新编译项目B;
二:用重载的方式重载多一个方法。
C想,用一的话如果有100个项目引用了这个类库,那我不是要编译100次?于是,C果断用了重载的方式实现。
好了,到这里你会不会有一个新的问题闪现在脑海中呢?C想,那引用类库A编译出来的两个项目B的执行文件有什么不同呢?于是C对此进行了测试,结果出乎C的意料:
// 这是引用类库A第一个版本,编译出来的项目B对A.Test.CallMethod的调用:
A.Test.CallMethod("Start");
// 这是引用类库A第二个版本,编译出来的项目B对A.Test.CallMethod的调用:
A.Test.CallMethod("Start", 1);
呵呵,项目B调用A.Test.CallMethod时竟然将参数的默认值编译到了项目B中,想想,如果某天C把默认值改成了2,那程序会 按修改后的值传入吗?肯定不会,除非重新引用A类库并重编译项目B。太坑爹了!好吧,微软提供了建议的调用代码,意思是要我们以一个默认值做参数,在使用 时若其值为默认值时替换为想定的值,如下:
// 参数是引用类型的版本
public static class Test {
public static void CallMethod(string message, object obj = null) {
Console.WriteLine("调用成功:" + message + (obj ?? new object()));
}
}
// 参数是值类型的版本
public static class Test {
public static void CallMethod(string message, int num = 0) {
Console.WriteLine("调用成功:" + message + (num == 0 ? 5 : num));
}
}
总结:增加方法但不要在原有的公开方法上做修改,即便是增加一个默认参数(就是一句废话)。

浙公网安备 33010602011771号