关于方法的重载和默认参数的一点小误区

有某类库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));
}
}

总结:增加方法但不要在原有的公开方法上做修改,即便是增加一个默认参数(就是一句废话)。

posted @ 2012-03-15 00:38  BlackTea  阅读(550)  评论(0)    收藏  举报