简体   繁体   English

扩展方法与静态方法优先级

[英]Extension method vs static method precedence

Consider the following program: 考虑以下程序:

class A
{
    public static void Foo()
    {
    }
}

static class Ext
{
    public static void Foo(this A a)
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        a.Foo();
    }
}

This fails to compile, with the error: 这无法编译,错误如下:

Member 'Test.A.Foo()' cannot be accessed with an instance reference; 无法使用实例引用访问成员'Test.A.Foo()'; qualify it with a type name instead 用类型名称来限定它

Why is the compiler ignoring the extension method? 为什么编译器会忽略扩展方法?

What you are trying to do isn't allowed. 你不想做什么。 The C# MSDN Extension Method Article specifically states that: C#MSDN扩展方法文章明确指出:

You can use extension methods to extend a class or interface, but not to override them. 您可以使用扩展方法来扩展类或接口,但不能覆盖它们。 An extension method with the same name and signature as an interface or class method will never be called. 永远不会调用与接口或类方法具有相同名称和签名的扩展方法。 At compile time, extension methods always have lower priority than instance methods defined in the type itself. 在编译时,扩展方法的优先级始终低于类型本身中定义的实例方法。

Thank goodness it isn't allowed as that would just be awful to have to maintain. 谢天谢地,这是不允许的,因为必须要保持这种可怕性。


EDIT: So people are saying that static methods aren't instance methods, which is correct. 编辑:所以人们说静态方法不是实例方法,这是正确的。 But try doing this: 但试着这样做:

class A
{
   public static void Foo() {}
   public void Foo() {}
}

That won't compile either because of a name ambiguity. 由于名称含糊不清,这也无法编译。 That is exactly what would happen if you were allowed to use the extension method. 如果允许您使用扩展方法,那就是会发生什么。 It would introduce the exact same ambiguity. 它会引入完全相同的歧义。 Now, given that one method is static and one is instance, should that mean that there is no ambiguity, perhaps. 现在,假设一个方法是静态的,一个是实例,那么这应该意味着没有歧义。 But at the current state it does introduce ambiguity which is yet another reason why it wouldn't be allowed. 但在目前的状态下,它确实引入了歧义,这也是为什么不允许它的另一个原因。

Edit #2: From a comment @ErenErsonmez made: 编辑#2:来自评论@ErenErsonmez:

However, as long as the extension method doesn't have the same signature as an instance method, I don't understand how it could ever cause ambiguity with a static method 但是,只要扩展方法与实例方法没有相同的签名,我就不明白它是如何用静态方法引起歧义的

If you change the signature of the extension method it will definitely work. 如果您更改扩展方法的签名,它肯定会起作用。 So the following will work: 所以以下内容将起作用:

class A
        {
            public static void Foo() { }
        }

    static class Ext
    {
        public static void Foo(this A me, int i)
        { }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
            a.Foo(10);

            Console.ReadLine();
        }
    }

So it looks more like the issue is an ambiguity one and not that there can't ever be an extension method of the same name as a method that already exists. 所以它看起来更像是一个含糊不清的问题而不是一个与已经存在的方法同名的扩展方法。

It appears from this MSDN article that this is due to security concerns. 这篇MSDN文章中可以看出,这是出于安全考虑。

I have often heard the concern that extension methods can be used to hijack or subvert the intended behavior of existing methods. 我经常听到担心扩展方法可能被用来劫持或破坏现有方法的预期行为。 Visual Basic addresses this by ensuring that, wherever possible, an instance method is preferable over an extension method. Visual Basic通过确保在可能的情况下,实例方法优于扩展方法来解决此问题。

The language allows extension methods to be used to create overloads for existing instance methods with different signatures. 该语言允许使用扩展方法为具有不同签名的现有实例方法创建重载。 This allows extension methods to be used to create overloads, while preventing the existing instance method from being overridden. 这允许使用扩展方法来创建重载,同时防止覆盖现有的实例方法。 If an extension method exists with the same signature as an instance method, the shadowing rules that are built into the compiler will prefer the instance method, therefore eliminating the possibility of an extension method overriding existing base class instance functionality 如果存在与实例方法具有相同签名的扩展方法,则编译器中内置的镜像规则将更喜欢实例方法,因此消除了扩展方法覆盖现有基类实例功能的可能性

This is VB focused (and instance focused), but still, the general idea is there. 这是以VB为重点(并且以实例为重点),但仍然是一般的想法。 Basically, the extension method takes the lowest precedence so that methods cannot be hijacked, and since the class already has a method signature for what you are trying to do, that takes precedence and throws the standard extension method error (when trying to call from an instance object). 基本上,扩展方法采用最低优先级,因此方法不能被劫持,并且由于类已经有一个方法签名用于您要执行的操作,因此优先级会引发标准扩展方法错误(当尝试从实例对象)。 You can never have two methods with the same signature, and that is what you are asking to be attempted here essentially...and allowing it would be a security concern as explained above already. 你永远不可能有两个具有相同签名的方法,这就是你要求在这里尝试的......并且如上所述,允许它将是一个安全问题。

Then, add the confusion that will be created by this, and it is just a bad idea to allow it. 然后,添加由此创建的混淆,允许它只是一个坏主意。

The problem is overload resolution: The static method Foo() is a candidate, it is applicable - just choosing it as best match will cause an error - which is exactly what happens. 问题是重载解决:静态方法Foo()是候选者,它是适用的 - 只选择它作为最佳匹配将导致错误 - 这正是发生的事情。 Extension methods are only candidates for overload resolution after all other candidates have been considered. 在考虑所有其他候选人之后,扩展方法仅是重载解决的候选者。 In the case of OPs problem case the extension method will not even have been considered before the error occurs. 在OPs问题的情况下,甚至在错误发生之前都不会考虑扩展方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM