为什么我必须使用“this”从扩展类中调用扩展方法?

时间:2009-10-23 22:41:39

标签: .net extension-methods

我已经编写了数十种扩展方法,它们都按预期工作。但这是我第一次在这种情况下使用扩展方法。

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

为什么'这个'。工作?

2 个答案:

答案 0 :(得分:5)

扩展方法不是成员“默认”查找的一部分 - 在检查扩展方法之前,您必须使用Target.Method形式的表达式。 this.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()调用实例成员静态成员(而不是指定实例或类型)这一事实可能是相关的。

答案 1 :(得分:0)

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

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

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