2009-10-23 166 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