c#可选参数的一个陷阱

一、背景:
互联网行业,为了降低部署风险,往往会将程序拆分成很多项目,编译成多个dll部署,这样修改的时候,只需要部署修改过的dll即可。
 
二、问题:
有一个函数,在很多个地方被使用:
public fun1(A a ,B b)
{
    //代码主体
}

 

突然有一天,有的地方调用的时候需要加入一个参数C c,但是又不想其他客户程序有任何变动,可以这样改:
方法一:使用可选参数
public fun1(A a ,B b,C c = 1)
{
 //代码主体
}

 

程序修改完后,在本地程序完美运行,将dll发测试。在测试环境,莫名其妙的报错。由于系统分层处理,web站点和Web API分离,错误返回到最上层,已经看不到错误原因,查了老半天日志,终于发现是另外一个dll调用了fun1函数,报找不到方法 fun1的错误。
 
 
将程序修改为:
方法二:重载
public fun1(A a ,B b)
{
    fun1(A a ,B b,1);
}
public fun1(A a ,B b,C c)
{
   //代码主体
}

 

重新发布dll,程序正常运行。
 
三、初步结论:
 
将代码修改成可选参数,客户程序需要重新编译,不然客户程序调用的时候会报找不到方法的错误。如果,客户程序太多,为了避免部署所有客户程序的dll,可以用方法二,重载的方法。
 
四、验证:
方法无默认参数:
 
c#可选参数的一个陷阱
 
c#可选参数的一个陷阱
 
方法有可选参数:
c#可选参数的一个陷阱
 
客户程序Program编译后的IL:
c#可选参数的一个陷阱
 
五、最终结论:
由图可知,客户程序的c#源码虽然没有变,但是编译后的IL中间代码确改变了,调用的函数也传了两个参数,并把函数默认参数888在客户程序声明,使用。
可以得出的结论是,C#可选参数函数其实是在编译的时候,在函数调用的地方做了处理,把默认参数传了进去。
 
六、现在问题来了,大家请思考
微软为什么要这样做呢?为什么不在编译的时候,像以下代码一样,做类似重载的处理呢? 这样的话就不用重新编译客户程序了
 
public fun1(A a ,B b)
{
    fun1(A a ,B b,1);
}
public fun1(A a ,B b,C c)
{
   //代码主体
}

 

 

c#可选参数的一个陷阱

上一篇:Non-ASCII characters are not allowed outside of literals and identifiers


下一篇:Python [Leetcode 344]Reverse String