昨天踩了一个坑。默认参数 + 增量发布的坑。

过程是这样的。

1. 有一个底层的方法,格式形如

void Test<T>(int p1, string p2, Func<T> p3){}

代码所在的项目的程序集名称假设为 A.dll

2. 引用这个方法的代码有多处,大部分分布在两个项目里面,对应的项目的程序集假设为B.dll和C.dll

3. 处于优化和解决bug的考虑,扩展了上述底层方法,改为:

void Test<T>(int p1, string p2, Func<T> p3, Func<T, bool> p4 = null){}

增加了第四个有默认值得参数。

这里提一下自己的理解误区:我一直以为上面的写法是等于:

void Test<T>(int p1, string p2, Func<T> p3){}

+

void Test<T>(int p1, string p2, Func<T> p3, Func<T, bool> p4){}

4. 改完了底层的那个方法后,重新编译获得A.dll,和相应调用了四个参数方法的代码所在的B.dll

5. 增量发布A.dll和B.dll。

...

6. 线上报错,异常信息提示源头为C.dll,异常明细是Method not found '!!0 Test(Int64, System.String, System.Func`1)'

7. 一脸懵逼 + 二脸懵逼 + 。。。 + 关它么事???

8. 差点准备回滚覆盖了。同事提醒,既然说它有问题,就更新它呗。依言照办,线上恢复。

轮到我百思不得其解了,为什么C.dll找不到这个方法呢?A里面不在呢吗?

后来我用反射工具查看了两个C.dll里面的代码。如下:

原始代码:

A.dll改之前,通过反编译看到的此处代码:

A.dll改成带默认参数之后:

重点在后面的那个null值。

也就是说,将函数Test后面追加了一个带默认值的参数后,相应原来调用时没有传第四个参数的地方,本质上是传了参数的,参数值为默认值。而函数的默认参数则像是一种语法糖,替程序员节省了输入null值的步骤,但是编译后的代码中,确实有的。

所以在上面的情况中,增量发布时,必须一起更新C.dll。否则,旧的DLL文件无法调用新的A.dll中的函数了。

补充一个。A.dll的反射获得的信息:

由上面这个图可以清晰的看到,这个函数,只有一个四个传参的定义,没有三个传参的重载。

相关阅读:

https://www.cnblogs.com/gdouzz/p/6889163.html

C#函数的默认参数——填坑记的更多相关文章

  1. Appium+python自动化(十三)- 输入中文 - 一次填坑记(超详解)

    简介 无论你在哪里,在做什么都会遇到很多坑,这些坑有些事别人挖的,有些是自己挖的.别人挖的叫坑人,自己挖的叫自杀,儿子挖的叫坑爹.因此在做app自动化道路上也不会是一帆风顺的,你会踩很多坑,这些坑和你 ...

  2. UiAutomator2.0升级填坑记

    UiAutomator2.0升级填坑记 SkySeraph May. 28th 2017 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph个人站点:www.sk ...

  3. Android项目开发填坑记-Fragment的onBackPressed

    Github版 CSDN版 知识背景 Fragment在当前的Android开发中,有两种引用方式,一个是 Android 3.0 时加入的,一个是supportV4包中的.这里简称为Fragment ...

  4. 浅谈html5 video 移动端填坑记

    这篇文章主要介绍了浅谈html5 video 移动端填坑记,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 本文介绍了html5 video 移动端填坑记,分享给大家,具体 ...

  5. Python默认参数的坑

    默认参数的坑 定义一个函数,传入一个list,添加一个end再返回 def add_end(L=[]): L.append('END') return L 正常调用时,结果似乎不错 print add ...

  6. Java web 开发填坑记 2 -如何正确的创建一个Java Web 项目

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72566261 本文出自[赵彦军的博客] Java web 开发填坑记 1-如何正确 ...

  7. C++中函数的默认参数

    使用方法: (1)在函数声明或定义时,直接对参数赋值,该参数就是默认参数. (2)在函数调用时,省略部分或全部参数,这时就会使用默认参数进行代替. 注意事项: (1)一般在声明函数是设置默认参数. 如 ...

  8. Android项目开发填坑记-Fragment的onAttach

    背景 现在Android开发多使用一个Activity管理多个Fragment进行开发,不免需要两者相互传递数据,一般是给Fragment添加回调接口,让Activity继承并实现. 回调接口一般都写 ...

  9. Android项目开发填坑记-so文件引发的攻坚战

    故事的最初 我负责的项目A要求有播放在线视频的功能,当时从别人的聊天记录的一瞥中发现百度有相关的SDK,当时找到的是Baidu-T5Player-SDK-Android-1.4s,项目中Demo的so ...

随机推荐

  1. golang单例模式

    1.定义:单例对象的类必须保证只有一个实例存在,全局有唯一接口访问. 2.分类: 懒汉方式:指全局的单例实例在第一次被使用时构建. 饿汉方式:指全局的单例实例在类装载时构建. 3.实现: (1)懒汉方 ...

  2. Android强制关闭某个指定应用 “关闭应用”

    强制关闭指定的应用程序: // 传入应用的包名即可kill掉应用 private void forceStopApp(String packageName) { ActivityManager am ...

  3. 潭州课堂25班:Ph201805201 django 项目 第二十九课 docker实例,文件下载前后台实现 (课堂笔记)

    docker 实例 :wq!保存退出 放入一个 html 文件 权限不够,加 sudo 查看本地仓库的 image 运行 docker -- name,后跟个运行名, -p 物理机端口映射到容器端口, ...

  4. C++程序设计方法3:派生类对象的构造和析构过程

    基类中的数据成员,通过继承成为派生类对象的一部分,需要在构造派生类对象的过程中调用基类构造函数来正确初始化: 若没有显示调用,则编译器会自动生成一个对基类的默认构造函数的调用. 若想要显示调用,则只能 ...

  5. Flask 三方组件 WTForms

    WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证 from flask import Blueprint from flask import request fro ...

  6. Spring Boot使用Druid连接池基本配置

    以下为Spring Boot配置Druid 一.pom.xml配置 <dependency> <groupId>com.alibaba</groupId> < ...

  7. arcgis pro指数库

    来自:https://pro.arcgis.com/zh-cn/pro-app/help/data/imagery/indices-gallery.htm 植被和土壤指数 MSAVI “修正土壤调节植 ...

  8. Unity2017灯光烘焙知识点

    去研究一下灯光探针,性能可以提升不少.

  9. curl: (51) Unable to communicate securely with peer: requested domain name does not match the server's certificate.报错

    curl https 网站 出现报错 解决办法: You can use the domain name as usual but override the resolver like so: cur ...

  10. Android开发中常见的设计模式 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...