views:

109

answers:

4

Can someone explain to me why in the following the 3rd invocation of DoSomething is invalid? ( Error message is "The name 'DoSomething' does not exist in the current context" )

public class A { }
public class B : A
{
    public void WhyNotDirect()
    {
        var a = new A();
        a.DoSomething();  // OK
        this.DoSomething();  // OK
        DoSomething(); // ?? Why Not
    }
}
public static class A_Ext
{
    public static void DoSomething(this A a)
    {
        Console.WriteLine("OK");
    }
}
+2  A: 

Because DoSomething takes a parameter.

DoSomething(a) would be legal.

Edit

I read the question a bit wrong here.

Since your calling it a a normal static method, and not a extension method, you need to prefic with the class name.

So A_Ext.DoSomething(a); will work.

If you call it like a normal static method, all the same rules apply.

Your second variant works because B inhetits A, and therefore you still end up calling it as an extension method, but the third does not.

sorry about the first version above that does not work. I'll leave it to keep the comment relevant.

Øyvind Bråthen
No it's not. Same Error.
My Other Me
Thanks: Edit noted.
My Other Me
+4  A: 

DoSomething requires an instance of A to do anything, and without a qualifier, the compiler can't see which DoSomething you need to invoke. It doesn't know to check in A_Ext for your method unless you qualify it with this.

nasufara
Why can it not reach that conclusion by itself? It "finds" the extension method when I reference "this." via the class hierarchy right? Surely it should be possible to do this without the "this." aspect?
My Other Me
I believe it's more about predictable behavior. It's better to have a qualifier and have the compiler know your intentions that to have it guess them for you.
nasufara
+1 for the answer and comment. C# is designed to err on the side of explicit qualification rather than have the compiler guess what you mean, even when there may seem to be a perfectly reasonable basis for an accurate guess. Check out Eric Lippert's blog (http://blogs.msdn.com/b/ericlippert/) for many, many examples of this decision-making process.
John M Gant
+2  A: 

Extension methods can be invoked like other static methods.

Change it to A_Ext.DoSomething(this).

If you're asking why it isn't implicitly invoked on this, the answer is that that's the way the spec was written. I would assume that the reason is that calling it without a qualifier would be too misleading.

SLaks
He's not concerned with solving the call. Using `this.` has already done that for him. He wants to understand why the one works when the other doesn't.
Joel Etherton
Thanks. I know how I can force it to invoke (this.), but I am trying to truly understand why it is required.
My Other Me
+2  A: 

Extension methods are still static methods, not true instance calls. In order for this to work you would need specific context using instance method syntax (from Extension Methods (C# Programming Guide))

In your code you invoke the extension method with instance method syntax. However, the intermediate language (IL) generated by the compiler translates your code into a call on the static method. Therefore, the principle of encapsulation is not really being violated. In fact, extension methods cannot access private variables in the type they are extending.

So while normally, both syntaxes would work, the second is without explicit context, and it would seem that the IL generated can't obtain the context implicitly.

Joel Etherton
This gives me the best insight so far I think. So basically because I could be invoking a method that could have the same name and signature in a base class and in the extension class, it might not know which one to choose in that case? That would make sense to me. Is that correct?
My Other Me
@My Other Me - As I read it, it wasn't an ambiguity problem so much as a signature issue. In the IL code, the extension method is still considered static. However, the compiler creates translation code that is context specific with respect to an instance. It looks like using `this` creates that context and without an instance specifier, the compiler is free to guess at the "best match" which would be the base class without the extension.
Joel Etherton