静态方法和扩展方法同名

2024-02-29

我创建了扩展方法:

public static class XDecimal
{
    public static decimal Floor(
        this decimal value,
        int precision)
    {
        decimal step = (decimal)Math.Pow(10, precision);
        return decimal.Floor(step * value) / step;
    }
}

现在我尝试使用它:

(10.1234m).Floor(2)

但编译器说Member 'decimal.Floor(decimal)' cannot be accessed with an instance reference; qualify it with a type name instead。我知道有静电decimal.Floor(decimal)方法。但它有不同的签名。为什么编译器无法选择正确的方法?


您在这里有两个很好且正确的答案,但我知道简单引用规范的答案并不总是那么具有启发性。让我添加一些额外的细节。

您可能有一个如下所示的重载解析心理模型:

  • 将所有可能的方法放在一个大桶中——扩展方法、静态方法、实例方法等。
  • 如果某些方法使用起来会出错,请将它们从桶中删除。
  • 在其余方法中,选择参数表达式与参数类型最匹配的唯一方法。

尽管这是许多人关于重载解决方案的心理模型,但遗憾的是它是微妙的错误。

真正的模型(我将在这里忽略泛型类型推断问题)如下:

  • 将所有实例和静态方法放在一个桶中。虚拟重写不计为实例方法。
  • 排除因实参与形参不匹配而不适用的方法。

此时我们要么有方法,要么没有。如果我们有任何方法的话不检查扩展方法。这是这里最重要的一点。模型是not“如果正常的重载解析产生错误,那么我们检查扩展方法”。该模型是“如果正常的重载解析没有产生任何适用的方法,那么我们检查扩展方法”。

如果桶中有方法,那么就会进一步消除基类方法,最后根据参数与参数的匹配程度选择最佳方法。

如果这恰好选择了静态方法,那么 C# 将假设您本想使用类型名称,但错误地使用了实例, 不是那个您想要搜索扩展方法。重载解析已经确定存在一个实例或静态方法,其参数与您提供的参数匹配,并且它将选择其中一个或给出错误;它不会说“哦,你可能想调用这个恰好在范围内的古怪扩展方法”。

我知道从您的角度来看这很令人烦恼。您显然希望模型是“如果重载解析产生错误,则回退到扩展方法”。在您的示例中,这很有用,但这种行为在其他情况下会产生不良结果。例如,假设你有类似的东西

mystring.Join(foo, bar);

这里给出的错误是应该是string.Join。如果 C# 编译器说“哦,string.Join是静态的。用户可能打算使用对字符序列进行连接的扩展方法,让我尝试一下...”然后您收到一条错误消息,指出序列连接运算符 - 这与您的代码无关——没有正确的论据。

或者更糟糕的是,如果出现奇迹,你did给它有效的参数,但打算调用静态方法,那么你的代码将以一种非常奇怪且难以调试的方式被破坏。

扩展方法是在游戏后期添加的,查找它们的规则使他们故意更喜欢给出错误而不是神奇地工作。这是一个安全系统,可确保扩展方法不会受到意外约束。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

静态方法和扩展方法同名 的相关文章

随机推荐