Why Is the 'This' Keyword Required to Call an Extension Method from Within the Extended Class

Why is the 'this' keyword required to call an extension method from within the extended class

A couple points:

First off, the proposed feature (implicit "this." on an extension method call) is unnecessary. Extension methods were necessary for LINQ query comprehensions to work the way we wanted; the receiver is always stated in the query so it is not necessary to support implicit this to make LINQ work.

Second, the feature works against the more general design of extension methods: namely, that extension methods allow you to extend a type that you cannot extend yourself, either because it is an interface and you don't know the implementation, or because you do know the implementation but do not have the source code.

If you are in the scenario where you are using an extension method for a type within that type then you do have access to the source code. Why are you using an extension method in the first place then? You can write an instance method yourself if you have access to the source code of the extended type, and then you don't have to use an extension method at all! Your implementation can then take advantage of having access to the private state of the object, which extension methods cannot.

Making it easier to use extension methods from within a type that you have access to is encouraging the use of extension methods over instance methods. Extension methods are great, but it is usually better to use an instance method if you have one.

Given those two points, the burden no longer falls on the language designer to explain why the feature does not exist. It now falls on you to explain why it should. Features have enormous costs associated with them. This feature is not necessary and works against the stated design goals of extension methods; why should we take on the cost of implementing it? Explain what compelling, important scenario is enabled by this feature and we'll consider implementing it in the future. I don't see any compelling, important scenario that justifies it, but perhaps there is one that I've missed.

Extension method requires this to call?


Is this normal or am I doing something wrong? Thanks.

This is normal. The extension method has to extend something. The compiler won't search for extension methods unless there is something as the "expression" (to the left of the ."). This is defined in the C# language spec, 7.6.5.2:

7.6.5.2 Extension method invocations

In a method invocation (§7.5.5.1) of one of the forms
expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )

Basically, you always need something for expr. In this case, this works, and the compiler can rewrite this as:

C . identifier ( expr ) 

Why we use this in Extension Methods?

Because that's the way you tell the compiler that it's an extension method in the first place. Otherwise it's just a normal static method. I guess they chose this so they didn't have to come up with a new keyword and potentially break old code.

Why do I have to use this to call an extension method from within the extended class?

Extension methods aren't part of the "default" lookup for members - you have to be using an expression of the form Target.Method before extension methods are checked. this.Foo() conforms to that requirement, so it works.

From section 7.5.5.2:

In a method invocation (§7.5.5.1) of
one of the forms

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args ) if the normal processing of the

invocation finds no applicable
methods, an attempt is made to process
the construct as an extension method
invocation.

Admittedly all that says is "the compiler is following the spec" rather than the reason why the spec was written that way... I don't know whether there is any specific reason, although the fact that you can invoke both instance members and static members using just Method() (instead of specifying either an instance or a type) may be relevant.

Why can't I call an extension method from a base class of the extended type‏?

Consider this situation:

public class Base
{
public void BaseMethod()
{

}
}

public class Sub : Base
{
public void SubMethod()
{

}
}

public static class Extensions
{
public static void ExtensionMethod(this Base @base) { }
}

Here are some interesting assertions about this code:

  • I cannot call the extension method using ExtensionMethod() from neither Base nor Sub.
  • I cannot call base.ExtensionMethod() from Sub.
  • I can call the extension method using Extensions.ExtensionMethod(this) from both Sub and Base.
  • I can call the extension method using this.ExtensionMethod() from both Sub and Base.

Why is this?

I don't have a conclusive answer, partly because there might not be one: as you can read in this thread, you have to add this. if you want to call it in the extension method style.

When you're trying to use an extension method from the type it is in (or - consequently - from a type that is derived from the type used in the extension method), the compiler doesn't realize this and will try to call it as a static method without any arguments.

As the answer states: they [the language designers] felt it was not an important use case scenario to support implicit extension methods (to give the beast a name) from within the type because it would encourage extension methods that really should be instance methods and it was considered plain unnecessary.

Now, it is hard to find out what is happening exactly under the covers but from some playing around we can deduce that base.X() does not help us. I can only assume that base.X performs its virtual call as X() and not this.X() from the context of the baseclass.

What do I do when I want to call the extension method of a baseclass from a subclass?

Frankly, I haven't found any truly elegant solution. Consider this scenario:

public class Base
{
protected void BaseMethod()
{
this.ExtensionMethod();
}
}

public class Sub : Base
{
public void SubMethod()
{
// What comes here?
}
}

public static class Extensions
{
public static void ExtensionMethod(this Base @base)
{
Console.WriteLine ("base");
}

public static void ExtensionMethod(this Sub sub)
{
Console.WriteLine ("sub");
}
}

There are 3 ways (leaving aside reflection) to call the ExtensionMethod(Base) overload:

  • Calling BaseMethod() which forms a proxy between the subclass and the extensionmethod.

You can use BaseMethod(), base.BaseMethod() and this.BaseMethod() for this since now you're just dealing with a normal instance method which in its turn will invoke the extension method. This is a fairly okay solution since you're not polluting the public API but you also have to provide a separate method to do something that should have been accessible in the context in the first place.

  • Using the extension method as a static method

You can also use the primitive way of writing an extension method by skipping the syntactic sugar and going straight to what it will be compiled as. Now you can pass in a parameter so the compiler doesn't get all confused. Obviously we'll pass a casted version of the current instance so we're targetting the correct overload:

Extensions.ExtensionMethod((Base) this);
  • Use the - what should be identical translation - of base.ExtensionMethod()

This is inspired by @Mike z's remark about the language spec which says the following:

At binding-time, base-access expressions of the form base.I and base[E] are evaluated exactly as if they were written ((B)this).I and ((B)this)[E], where B is the base class of the class or struct in which the construct occurs. Thus, base.I and base[E] correspond to this.I and this[E], except this is viewed as an instance of the base class.

The spec literally says that base.I will be invoked as ((B) this).I. However in our situation, base.ExtensionMethod(); will throw a compilation error while ((Base) this).ExtensionMethod(); will work perfectly.

It looks like something is wrong either in the documentation or in the compiler but that conclusion should be drawn by someone with deeper knowledge in the matter (paging Dr. Lippert).

Isn't this confusing?

Yes, I would say it is. It kind of feels like a black hole within the C# spec: practically everything works flawlessly but then suddenly you have to jump through some hoops because the compiler doesn't know to inject the current instance in the method call in this scenario.

In fact, intellisense is confused about this situation as well:

Sample Image

We have already determined that that call can never work, yet intellisense believes it might. Also notice how it adds "using PortableClassLibrary" behind the name, indicating that a using directive will be added. This is impossible because the current namespace is in fact PortableClassLibrary. But of course when you actually add that method call:

Sample Image

and everything doesn't work as expected.

Perhaps a conclusion?

The main conclusion is simple: it would have been nice if this niche usage of extension methods would be supported. The main argument for not implementing it was because it would encourage people to write extension methods instead of instance methods.

The obvious problem here is of course that you might not always have access to the base class which makes extension methods a must but by the current implementation it is not possible.

Or, as we've seen, not possibly with the cute syntax.

Extension method - having to use this keyword?


I thought that methods/attributes of
this were inherently in the default
scope.

They are. But extension methods are not methods of this in the default scope; they are static methods accessible via syntactic sugar provided as a courtesy by the compiler.

I believe you already know this, but just to clarify: if ExtensionMethod is an extension method of the class whose scope you're currently in, typing this:

this.ExtensionMethod();

...is the same as:

SomeStaticClass.ExtensionMethod(this);

this needs to be passed as a parameter to ExtensionMethod. The first way above, the compiler simply does this for you.

Naturally, they could have implemented things differently so that the compiler "brings in" extension methods as well as class members into the default scope; they just simply chose not to. Personally, I like that; but I guess it's a subjective matter. Anyway, if you dislike having to type this, it's only a small annoyance, right?

Accessing extension method within extended type?

Firstly, I'll note that there are perfectly good reasons to call extension methods on this. For example, you might be writing a collection class and want to use LINQ within it. Nothing wrong with that. Now, in terms of the question:

Why did I have to qualify the extension method since modern compilers remove the need for qualifying fields, properties, and methods with the this keyword?

It's not a matter of the modernity of the compiler - it's about what the language specification says. From ECMA-334, section 12.7.6.3:

In a method invocation (§12.6.6.2) of one of the forms

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )

if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. If expr or any of the args has compile-time type dynamic, extension methods will not apply.

A method call of the form Method() is not in one of those forms, as there's no expr.

So the compiler's just obeying the rules of the specification. As for why it's designed that way, that's slightly different. I don't know the details of this (although I can see if they're in one of the annotated versions of the spec) but I suspect that the fact that Foo() can either refer to an instance method or a static method in the current class or any of the base classes makes the whole thing a little trickier. (As of C# 6 it could also be a static method in any of the methods imported by a using static directive, mind you...)

Using extension methods from within the class they extend


I can omit this when referencing properties and methods, so why can't I do this...?

It's just part of how extension methods are invoked, basically. Section 7.6.5.2 of the C# specification (Extension Method Invocations) starts:

In a method invocation (7.5.5.1) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation.

Without the this, your invocation wouldn't be of that form, so that section of the spec wouldn't apply.

This isn't a justification of why the feature was designed that way, of course - it's a justification of the compiler's behaviour in terms of correctness.



Related Topics



Leave a reply



Submit