为什么这里需要“this”(扩展方法)?

4

元注:搜索单词“this”是不可能的。

我在ASP.NET中遇到了一个奇怪的场景,需要使用this关键字。但这不是为了解决本地和实例变量之间的冲突,就像在构造函数中看到的那样。

Microsoft.Web.Mvc包含一个名为ControllerExtensions的类,我正在使用RedirectToAction(Expression<Action<TController>> action)重载。也许这很特别,因为重载是扩展。

RedirectToAction(c => c.Index())无法编译,并且它说Cannot convert lambda expression to type 'string' because it is not a delegate type。现在,这听起来像是它认为我正在使用第一个接受字符串的重载。

this.RedirectToAction(c => c.Index())可以编译通过。我还可以静态调用它,将this作为第一个参数传递。

  1. 为什么编译器不能弄清楚我正在寻找接受表达式的重载并使用它?因为该方法需要涉及一个动作的表达式,而不仅仅是一个动作。我完全不理解Expressions命名空间,所以不知道使用这个参数类型的目的。

  2. 无论问题1的答案如何,为什么简单地添加this就可以解决所有问题?


1
这个类是派生类吗? - Gregory A Beamer
好的,我在一个控制器中,所以是的。使用this,编译器会在检查基类之前搜索我的方法吗?那就可以解释了吗? - Tesserex
这,顺便说一下,是一个更好的理由总是在实现内部使用 this. ;) 我知道这是一个有争议的StyleCop指导,但我实际上认为这是一个很好的建议,因为它完全避免了类似这样的奇怪问题。 - Reed Copsey
3个回答

4

扩展方法的工作方式如下。

根据C#规范 (7.6.5.2 扩展方法调用),只有在调用符合以下“形式”之一时才会使用扩展方法:

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )

这基本上意味着你总是需要在 "." 的左边有一些东西,才能让编译器解析扩展方法。表达式 expr. 部分必须存在(且不能为 dynamic),编译器才会查找扩展方法。
例如,这里是一个小测试,可以演示:
namespace TestNamespace
{
    using System;

    public static class TextExtension
    {
        public static void Print(this Test test)
        {
            Console.WriteLine("Found");
        }
    }

    public class Test
    {
        public void Foo()
        {
            // Compiler error!
            Print();

            // Works fine
            this.Print();
        }

        static void Main()
        {
            Test test = new Test();
            test.Foo();

            // Fine here
            test.Print();
            Console.ReadKey();
        }
    }
}

注意编译器错误 - 由于我们在Test实例内部,所以不能直接调用Print(),必须使用this.。但是,我们可以很容易地在Test中执行test.Print()(或在Test内部执行this.Print())。

这么基础的东西,我居然没注意到?我真的从来没有尝试过在当前对象上调用扩展方法吗?奇怪... - Tesserex
@Tesserex:这是一些非常基础的东西,但很少见。如果您正在定义自己的类型,那么很少会在自己的对象中使用扩展方法,因为您可以添加一个实例方法代替... - Reed Copsey

0
我可以回答第二个问题:你的类(this)只有一个RedirectToAction方法,所以没有歧义。我敢打赌,如果你重载了String方法,你会再次遇到这个错误。

@Reed:是的,当我看到你的答案时,我意识到了这一点。顺便加个赞。 - trutheality

0

这里存在歧义。

当你使用'this'时,你调用了这个方法 -

Controller.RedirectToAction

没有 'this',你就会调用扩展方法 -

Microsoft.Web.Mvc.ControllerExtensions.RedirectToAction

实际上,它的行为方式相反。如果没有这个,它就不会使用扩展重载。有了这个,它就是正确的。 - Tesserex
据我所知,当你使用“this”时,你是在调用该方法的类中使用它,而在这种情况下,是Controller类。 - Maxim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接