10

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; qualify it with a type name instead

Why is the compiler ignoring the extension method?

user
  • 5,335
  • 7
  • 47
  • 63
Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • Why would you want to do this? It has the potential to lead to massive confusion! – Jetti Mar 28 '12 at 18:32
  • 1
    Should this be functioning code you would be introducing a level of ambiguity that is difficult for a human to understand, let alone the machine to interpret your intention. I don't see that this is an actual issue. If you want to call the external static method that applies this logic instead of relying on an overlapping prototyping system you would probably want to call the method directly: `Ext.Foo(a);` so the intent is clear to all involved. – Quintin Robinson Mar 28 '12 at 18:35
  • 2
    You can see [this answer][1] [1]: http://stackoverflow.com/questions/160118/static-and-instance-methods-with-the-same-name Regards –  Mar 28 '12 at 18:45
  • You can see [this answer][1] [1]: http://stackoverflow.com/questions/160118/static-and-instance-methods-with-the-same-name –  Mar 28 '12 at 20:57

3 Answers3

5

What you are trying to do isn't allowed. The C# MSDN Extension Method Article specifically states that:

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:

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.

Neel
  • 11,625
  • 3
  • 43
  • 61
Jetti
  • 2,418
  • 1
  • 17
  • 25
  • Static methods aren't overridable in the first place. This quote talks about overriding instance methods with extension method syntax, but the question asks why a static method is chosen over an extension method in a seemingly instance-level invocation. Unless the distinction between static and instance methods is irrelevant here, in which case someone could elaborate on that. – BoltClock Mar 28 '12 at 18:43
  • @BoltClock I have added an edit. The problem isn't limited to extension methods. If I tried to create an instance method with the same name and return type, I will get an error because there is already a method with the same parameter types. The extension methods would cause this problem as well. – Jetti Mar 28 '12 at 18:49
  • the ambiguity in your example makes sense because if you change the instance method like 'public void Foo(){Foo();}', the compiler can't tell if it's a recursive call or call to the static method. 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. Maybe this is just a limitation we have to live with for now -- not that it is a terrible limitation... – Eren Ersönmez Mar 28 '12 at 19:14
  • @ErenErsonmez If you change the method signature of the extension method it will work. I'll add that in an edit – Jetti Mar 28 '12 at 19:29
3

It appears from this MSDN article that this is due to security concerns.

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.

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. 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.

Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • 1
    it makes perfect sense that instance methods take precedence, which this article is talking about. however, the example in question is about a static method taking precedence over an extension method _on an object instance_. – Eren Ersönmez Mar 28 '12 at 18:41
  • @ErenErsonmez But the point is more that the method signature inside the class (static or instance) takes precedence. I will try to clarify this further in my answer. – Justin Pihony Mar 28 '12 at 18:45
  • @ErenErsonmez as I state in my edit to my question, this isn't an extension method issue but an issue that you can't have two methods with the same name and parameter types in the same class. The extension method would create an ambiguity issue for this class if it were allowed to be used. – Jetti Mar 28 '12 at 18:51
3

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. 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.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • This is how I'm interpreting §7.6.5.2 of the spec. Could you explain what "applicable" means, though? I'm having trouble figuring that out. – BoltClock Mar 28 '12 at 18:47
  • 1
    Extension methods are candidates for overload resolution *after non-extension methods have been tried*. The compiler may still have to resolve overloaded extension methods! – Jon Skeet Mar 28 '12 at 20:06
  • Ok, after looking at the spec, this explanation makes sense. If I understand §7.6.5.2 correctly, member lookup of Foo on A occurs independent of the instance expression ("a"). The resulting method group is associated with the instance expression _after_ the member lookup. At first, it didn't make sense to me why a static member would even be a candidate when the function was being called on an instance, but I think I see how that works. – Eren Ersönmez Mar 30 '12 at 05:53
  • correction... I was looking at **7.4 Member lookup**, not §7.6.5.2. – Eren Ersönmez Mar 30 '12 at 09:00