Why do I have to use "this" to call an extension method from within the extended class?
I've written dozens of extension methods and they all work as expected. But this is the first time I ran into using an extension method in this context.
public static class ControllerExtensions
{
public static RedirectToRouteResult RedirectToAction<TController>(
this Controller controller
, Expression<Action<TController>> action
) where TController : Controller
{
RouteValueDictionary routeValuesFromExpression =
ExpressionHelper.GetRouteValuesFromExpression<TController>(action);
return new RedirectToRouteResult(routeValuesFromExpression);
}
}
Looks normal enough, right? But within my controllers, I cannot access this extension method by typing. Instead, I have to prefix it with the keyword "this". For example:
// This does not work, I get a compiler error because
// RedirectToAction has no overload for the generic.
//
return
RedirectToAction<MembershipController>(
c => c.RegisterSuccess(Server.UrlEncode(code) ));
// But, this does work?!?!
//
return
this.RedirectToAction<MembershipController>(
c => c.RegisterSuccess(Server.UrlEncode(code) ));
Very odd. Perhaps it is because I am within the instance object I am extending? The "controller" instance that is?
Sure enough, I was able to duplicate it in a simple console app:
class Program
{
static void Main(string[] args)
{
var x = new TestClass();
x.Go<String>();
}
}
public class TestClass
{
public void Go()
{
}
public void NextMethod()
{
// compiler erro开发者_如何学编程r. :(
Go<String>();
// works!
this.Go<String>();
}
}
public static class TestExtension
{
public static string Go<T>(this TestClass theClass)
{
return String.Empty;
}
}
So why does 'this.' work?
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.
I think is because of how extension methods works.
When you write Go(), the compiler assumes that Go is a method in the current class, which isn't.
Extension methods are 'attached' to a instance, and you specify the instance using the this keyword.
精彩评论