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

edu*_*911 1 .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);
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来很正常吧?但在我的控制器中,我无法通过键入来访问此扩展方法.相反,我必须在前面添加关键字"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) ));
Run Code Online (Sandbox Code Playgroud)

很奇怪.也许是因为我在我正在扩展的实例对象中?"控制器"实例是什么?

果然,我能够在一个简单的控制台应用程序中复制它:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

那么为什么'这个'.工作?

Jon*_*eet 6

扩展方法不是成员的"默认"查找的一部分 - 您必须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
Run Code Online (Sandbox Code Playgroud)

调用找不到适用的方法,尝试将构造作为扩展方法调用进行处理.

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

  • 例如,您可以争辩说,扩展方法应该支持向您无法控制的现有类添加其他功能 - 如果您的对象依赖于特定的扩展方法,那么它应该内置于主类定义中,而不是依赖于弱而且可能易碎的依赖. (2认同)