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

发布于 2024-08-08 23:27:38 字数 1633 浏览 5 评论 0原文

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

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

那为什么是“this.”呢?工作?

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 error.  :(
        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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

叹梦 2024-08-15 23:27:38

扩展方法不是成员“默认”查找的一部分 - 在检查扩展方法之前,您必须使用 Target.Method 形式的表达式。 this.Foo() 符合该要求,因此它可以工作。

来自第 7.5.5.2 节:

在方法调用(§7.5.5.1)中
其中一种形式

<前><代码>表达式。标识符 ( )
表达式。标识符 (args)
表达式。标识符<类型参数 > ( )
表达式。标识符<类型参数 > ( args ) 如果正常处理

调用发现不适用
方法,尝试处理
作为扩展方法的构造
调用。

诚然,所有这些都说的是“编译器遵循规范”,而不是规范以这种方式编写的原因......我不知道是否有任何具体原因,尽管事实是您可以仅使用 Method() (而不是指定实例或类型)来调用实例成员和静态成员可能是相关的。

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.

清引 2024-08-15 23:27:38

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

当您编写 Go() 时,编译器假定 Go 是当前类中的方法,但事实并非如此。

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文