静态方法和扩展方法同名 [英] Static method and extension method with same name

查看:103
本文介绍了静态方法和扩展方法同名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了扩展方法:

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)方法.但是它具有不同的签名.为什么编译器无法选择正确的方法?

But compiler says Member 'decimal.Floor(decimal)' cannot be accessed with an instance reference; qualify it with a type name instead. I understand there is static decimal.Floor(decimal) method. But it has different signature. Why compiler is unable to choose correct method?

推荐答案

您在这里有两个很好且正确的答案,但我知道仅引用规范的答案并不总是那么具有启发性.让我添加一些其他详细信息.

You have two good and correct answers here, but I understand that answers which simply quote the specification are not always that illuminating. Let me add some additional details.

您可能有一个重载解决方案的心理模型,如下所示:

You probably have a mental model of overload resolution that goes like this:

  • 将所有可能的方法放在一个大桶中-扩展方法,静态方法,实例方法等.
  • 如果存在使用错误的方法,请从存储桶中删除它们.
  • 在其余方法中,选择一种最能使参数表达式与参数类型匹配的唯一方法.

尽管这是许多人解决过载的心理模型,但遗憾的是,它是错误的.

Though this is many people's mental model of overload resolution, regrettably it is subtly wrong.

真实模型-我将在这里忽略泛型类型推断问题-

The real model -- and I will ignore generic type inference issues here -- is as follows:

  • 将所有实例和静态方法放入存储桶中.虚拟替代不算作实例方法.
  • 消除由于参数与参数不匹配而导致不适用的方法.

在这一点上,我们要么在存储桶中有方法,要么没有.如果我们在存储桶中根本没有任何方法,那么扩展方法不会被检查.这是重要的一点.该模型不是不是如果正常的过载解决方案产生了错误,那么我们将检查扩展方法".该模型是如果正常的过载解决方法没有产生任何适用的方法,那么我们将检查扩展方法".

At this point we either have methods in the bucket or we do not. If we have any methods in the bucket at all then extension methods are not checked. This is the important bit right here. The model is not "if normal overload resolution produced an error then we check extension methods". The model is "if normal overload resolution produced no applicable methods whatsoever then we check extension methods".

如果存储桶中有方法,则可以消除基类方法,最后根据参数与参数的匹配程度来选择最佳方法.

If there are methods in the bucket then there is some more elimination of base class methods, and finally the best method is chosen based on how well the arguments match the parameters.

如果碰巧选择了一个静态方法,则C#会假定您打算使用类型名称并错误地使用了一个实例,而不是您希望搜索扩展方法.重载解析已经确定存在一个实例或静态方法,其参数与您提供的参数相匹配,并且它将选择其中一个或给出错误;它不会说哦,您可能打算调用这个恰好在范围内的古怪扩展方法".

If this happens to pick a static method then C# will assume that you meant to use the type name and used an instance by mistake, not that you wish to search for an extension method. Overload resolution has already determined that there is an instance or static method whose parameters match the arguments you gave, and it is going to either pick one of them or give an error; it's not going to say "oh, you probably meant to call this wacky extension method that just happens to be in scope".

我了解从您的角度来看这令人烦恼.您显然希望模型是如果重载解析产生错误,请使用扩展方法".在您的示例中这将很有用,但是在其他情况下,此行为会导致不良结果.例如,假设您有类似

I understand that this is vexing from your perspective. You clearly wish the model to be "if overload resolution produces an error, fall back to extension methods". In your example that would be useful, but this behaviour produces bad outcomes in other scenarios. For example, suppose you have something like

mystring.Join(foo, bar);

此处给出的错误是应该为string.Join.如果C#编译器说哦,string.Join是静态的.用户可能打算使用确实对字符序列进行连接的扩展方法,让我尝试一下……",那将是奇怪的,然后您收到一条错误消息说序列连接运算符-与此处的代码无关-没有正确的参数.

The error given here is that it should be string.Join. It would be bizarre if the C# compiler said "oh, string.Join is static. The user probably meant to use the extension method that does joins on sequences of characters, let me try that..." and then you got an error message saying that the sequence join operator -- which has nothing whatsoever to do with your code here -- doesn't have the right arguments.

或更糟糕的是,如果您奇迹般地给了 did 给它可行的参数,但希望调用静态方法,那么您的代码将以一种非常奇怪且难以调试的方式被破坏

Or worse, if by some miracle you did give it arguments that worked but intended the static method to be called, then your code would be broken in a very bizarre and hard-to-debug way.

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

Extension methods were added very late in the game and the rules for looking them up make them deliberately prefer giving errors to magically working. This is a safety system to ensure that extension methods are not bound by accident.

这篇关于静态方法和扩展方法同名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆