添加可选参数是否会更改方法签名,是否会触发方法缺少exception?
我们有几个引用库程序集的项目让我们调用“myUtil”,现在是几个项目中引用的方法之一,
GetData(int p1, string p2, object p3, bool p4 = false);
现在,如果我改变上述方法,
GetData(int p1, string p2, object p3, bool p4 = false, bool p5 = false);
我是否必须将“myUtil.dll”程序集更新为引用它的项目?
没有引用它我得到这个错误,这确实有意义,并在我更新引用时消失, 但我不能有效查找引用,它说你必须更新引用
System.MissingMethodException:找不到方法:’Void GetData(….
必须更新所有引用。
可选参数只是语法糖。
当你有这个:
GetData(int p1, string p2, object p3, bool p4 = false);
并称之为:
GetData(1, "p2", obj);
编译器执行此操作:
GetData(1, "p2", obj, false);
您需要重新编译并重新部署引用它的所有程序集/项目。
您不需要删除并重新添加引用,但您需要重建所有针对DLL编译的项目。 添加可选参数是源兼容但不是二进制兼容的更改,因为编译器在调用站点发出不同的IL,以包含正常的默认值 – 无论可选参数是否,IL中的调用本身看起来都相同省略与否。
例如,请考虑以下代码:
class Test { static void Main() { Foo(3); Foo(); } static void Foo(int x = 5) { } }
IL for Main
看起来像这样:
.method private hidebysig static void Main() cil managed { .entrypoint // Code size 16 (0x10) .maxstack 8 IL_0000: nop IL_0001: ldc.i4.3 IL_0002: call void Test::Foo(int32) IL_0007: nop IL_0008: ldc.i4.5 IL_0009: call void Test::Foo(int32) IL_000e: nop IL_000f: ret } // end of method Test::Main
如您所见,常量5 在Main
方法中加载并作为参数传递,就像显式为3一样。 在assembly边界上发生同样的事情。
相同的规则也适用于更改常量的值,以及更改可选参数的默认值 – 所有这些都需要客户端重建。
如果停止使用可选参数并使用方法重载,则可以保持兼容性:
public void GetData(int p1, string p2, object p3, bool p4 = false, bool p5 = false) { //Do something }
变
public void GetData(int p1, string p2, object p3) { GetData(p1, p2, p3, false); } public void GetData(int p1, string p2, object p3, bool p4) { GetData(p1, p2, p3, p4, false); } public void GetData(int p1, string p2, object p3, bool p4, bool p5) { //Do something }
但是,除非重新编译所有项目,否则这不会反映默认值的更改。 例如,任何旧的GetData(1, "2", null)
将始终调用新的GetData(1, "2", null, false)
即使您更改
public void GetData(int p1, string p2, object p3) { GetData(p1, p2, p3, false); }
至
public void GetData(int p1, string p2, object p3) { GetData(p1, p2, p3, true); }