2009-10-23 127 views
0

我写了几十种扩展方法,它们都按预期工作。但这是我第一次碰到这种情况下使用扩展方法。为什么我必须使用“this”从扩展类中调用扩展方法?

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); 
    } 
} 

看起来很正常吧?但在我的控制器中,我无法通过输入来访问此扩展方法。相反,我必须在关键字“this”前加上前缀。例如:

// 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))); 

很奇怪。也许这是因为我在我正在扩展的实例对象内? “控制器”实例是?

果然,我能复制它在简单的控制台应用程序:“这个”

class Program 
{ 
    static void Main(string[] args) 
    { 
     var x = new TestClass(); 
     x.Go<String>(); 
    } 
} 

public class TestClass 
{ 
    public void Go() 
    { 
    } 

    public void NextMethod() 
    { 
     // compiler error. :(
     Go<String>(); 

     // works! 
     this.Go<String>(); 
    } 
} 

public static class TestExtension 
{ 
    public static string Go<T>(this TestClass theClass) 
    { 
     return String.Empty; 
    } 
} 

那么,为什么工作?

+0

这与ASP.NET或MVC控制器无关。我改变了问题标题和标签。 – M4N

回答

5

扩展方法不是成员的“默认”查找的一部分 - 您必须在检查扩展方法之前使用表单Target.Methodthis.Foo()符合该要求,所以它的工作原理。

从节7.5.5.2:

在方法调用(第7.5.5.1节)的形式

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

调用没有发现适用 方法 之一,试图处理 该构造作为扩展方法 调用。

诚然一切说的是“编译器是继规范”,而不是为什么规范写这样的原因......我不知道是否有任何具体的原因,但事实您可以调用实例成员仅使用Method()(而不是指定实例或类型)的静态成员可能是相关的。

+2

例如,你可能会争论说,扩展方法应该支持为你不控制的现有类添加额外的功能 - 如果你的对象依赖于特定的扩展方法,那么它应该内置到主类定义中,而不是比依靠弱和可能破坏的依赖。 – Rob

+0

谢谢你的回复和评论。 – eduncan911

0

我认为是因为扩展方法的工作原理。

当您编写Go()时,编译器会假定Go是当前类中的方法,而不是。

扩展方法“附加”到实例,并且使用this关键字指定实例。

+0

感谢您的回答。 Jon实际上通过指定编译器以Target.Method形式从规范开始工作来正确回答它。 – eduncan911