您在这里有两个很好且正确的答案,但我知道简单引用规范的答案并不总是那么具有启发性。让我添加一些额外的细节。
您可能有一个如下所示的重载解析心理模型:
- 将所有可能的方法放在一个大桶中——扩展方法、静态方法、实例方法等。
- 如果某些方法使用起来会出错,请将它们从桶中删除。
- 在其余方法中,选择参数表达式与参数类型最匹配的唯一方法。
尽管这是许多人关于重载解决方案的心理模型,但遗憾的是它是微妙的错误。
真正的模型(我将在这里忽略泛型类型推断问题)如下:
- 将所有实例和静态方法放在一个桶中。虚拟重写不计为实例方法。
- 排除因实参与形参不匹配而不适用的方法。
此时我们要么有方法,要么没有。如果我们有任何方法的话不检查扩展方法。这是这里最重要的一点。模型是not“如果正常的重载解析产生错误,那么我们检查扩展方法”。该模型是“如果正常的重载解析没有产生任何适用的方法,那么我们检查扩展方法”。
如果桶中有方法,那么就会进一步消除基类方法,最后根据参数与参数的匹配程度选择最佳方法。
如果这恰好选择了静态方法,那么 C# 将假设您本想使用类型名称,但错误地使用了实例, 不是那个您想要搜索扩展方法。重载解析已经确定存在一个实例或静态方法,其参数与您提供的参数匹配,并且它将选择其中一个或给出错误;它不会说“哦,你可能想调用这个恰好在范围内的古怪扩展方法”。
我知道从您的角度来看这很令人烦恼。您显然希望模型是“如果重载解析产生错误,则回退到扩展方法”。在您的示例中,这很有用,但这种行为在其他情况下会产生不良结果。例如,假设你有类似的东西
mystring.Join(foo, bar);
这里给出的错误是应该是string.Join
。如果 C# 编译器说“哦,string.Join
是静态的。用户可能打算使用对字符序列进行连接的扩展方法,让我尝试一下...”然后您收到一条错误消息,指出序列连接运算符 - 这与您的代码无关——没有正确的论据。
或者更糟糕的是,如果出现奇迹,你did给它有效的参数,但打算调用静态方法,那么你的代码将以一种非常奇怪且难以调试的方式被破坏。
扩展方法是在游戏后期添加的,查找它们的规则使他们故意更喜欢给出错误而不是神奇地工作。这是一个安全系统,可确保扩展方法不会受到意外约束。