最近,我想在扩展方法中添加一个可选参数.原始方法看起来像这样:
public static class Extensions {
public static bool Foo(this IFoo target) {
target.DoIt(true);
}
}
Run Code Online (Sandbox Code Playgroud)
这显然是一个简化版本,但让我们继续.
我做的是:
public static class Extensions {
public static bool Foo(this IFoo target, bool flag = true) {
target.DoIt(flag);
}
}
Run Code Online (Sandbox Code Playgroud)
我所做的就是引入一个带有默认值的可选参数,对吧?我期待的是编译器生成重载方法,没有标志.这部分发生了.我重新编译的任何代码都能够编译和执行而没有任何问题,即使没有像这样的参数:
...
IFoo foo = new FooBar();
foo.Foo();
...
Run Code Online (Sandbox Code Playgroud)
但是,任何针对以前版本的Foo()构建的代码都不起作用,抛出以下异常:
Unhandled Exception: System.MissingMethodException: Method not found: 'Boolean Models.Class1.Foo()'.
at DefaultParamsTests.Program.Main(String[] args)
Run Code Online (Sandbox Code Playgroud)
这对我们来说显然是一个问题,因为我们有一个公共API,我们的客户可以利用它,这将是一个突破性的变化.
解决方案是明确创建一个重载:
public static class Extensions {
public static bool Foo(this IFoo target) {
target.DoIt(true);
}
public static bool Foo(this IFoo target, bool ) {
target.DoIt(true);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,Resharper建议我可以为方法foo引入一个可选参数.

如果我遵循重构它基本上做了我上面显示的.但是,这对现有代码不起作用.

我使用Reflector和dotPeek查看了生成的IL.两者都没有显示过载的产生.
我错过了什么?
在默认参数的情况下,实际调用站点被重写以使用默认值。这意味着根本不会生成重载,您的调用代码已被修改!
public void fun(int x = 3) { }
// in another file
fun(); // compiler re-writes to fun(3);
fun(7); // fun(7) as expected
// actual code generated by the c# compiler
fun(3);
fun(7);
Run Code Online (Sandbox Code Playgroud)
如果在 C# 中使用可选参数,则需要在function更改时重新编译所有调用方。出于这个原因,强烈建议不要将这些类型的方法放在公共接口上(例如,由其他代码调用)。在您自己的链接项目中使用它们很好,因为它们应该同时编译