为什么从扩展类中调用扩展方法需要'this'关键字

时间:2010-08-18 10:11:20

标签: c# extension-methods

我已经为ASP.NET MVC ViewPage创建了一个扩展方法,例如:

public static class ViewExtensions
{
    public static string Method<T>(this ViewPage<T> page) where T : class
    {
        return "something";
    }
}

从View(从ViewPage派生)调用此方法时,我收到错误“ CS0103:当前上下文中不存在名称'Method'”除非我使用要调用它的this关键字:

<%: Method() %> <!-- gives error CS0103 -->
<%: this.Method() %> <!-- works -->

为什么需要this关键字?或者没有它可以工作,但我错过了什么?

(我认为必须有这个问题的重复,但我找不到一个)

更新

作为Ben Robinson says,调用扩展方法的语法只是编译器糖。那么为什么编译器不能自动检查当前类型的基类型的扩展方法而不需要this关键字呢?

6 个答案:

答案 0 :(得分:48)

几点:

首先,建议的功能(在扩展方法调用上隐含“this。”)是不必要的。 LINQ查询理解需要扩展方法才能按照我们想要的方式工作;接收器总是在查询中声明,因此没有必要支持隐式,以使LINQ工作。

其次,该功能反对更广泛的扩展方法设计:即,扩展方法允许您扩展自己无法扩展的类型,因为它是一个接口,你不知道实现,或者因为你知道实现但没有源代码。

如果您正在使用该类型中的类型的扩展方法,则 可以访问源代码。 为什么你首先使用扩展方法?如果你有权访问扩展类型的源代码,你可以自己编写一个实例方法,然后你根本不必使用扩展方法!然后,您的实现可以利用对对象的私有状态的访问权限,而扩展方法则无法访问。

在您有权访问的类型中更容易使用扩展方法,这鼓励在实例方法上使用扩展方法。扩展方法很棒,但如果你有一个实例方法通常更好。

考虑到这两点,负担不再落在语言设计者身上,无法解释为什么存在。现在可以解释为什么应该。功能与它们相关的成本很高。此功能不是必需的,并且违反了扩展方法的规定设计目标;我们为什么要承担实施它的成本?说明此功能启用了哪些引人注目的重要方案,我们将考虑将来实施它。我没有看到任何令人信服的重要场景证明这一点,但也许有一个我错过了。

答案 1 :(得分:7)

如果没有它,编译器只会将其视为静态类中的静态方法,该方法将页面作为第一个参数。即。

// without 'this'
string s = ViewExtensions.Method(page);

VS

// with 'this'
string s = page.Method();

答案 2 :(得分:6)

在实例方法中,'this'以透明方式隐式传递给每个方法,因此您可以访问它提供的所有成员。

扩展方法是静态的。通过调用Method()而不是this.Method()Method(this),您不会告诉编译器传递给方法的内容。

你可能会说'为什么它只是意识到调用对象是什么并将其作为参数传递?'

答案是扩展方法是静态的,可以从静态上下文中调用,其中没有“this”。

我猜他们可以在编译期间检查这一点,但说实话,这可能需要付出极大的回报。说实话,我认为在取消一些扩展方法调用的显式方面没什么好处。事实上,它们可能被误认为是方法,这意味着它们有时可能非常不直观(例如,不会抛出NullReferenceExceptions)。我有时会认为他们应该为扩展方法引入一个新的“管道前移”式操作符。

答案 3 :(得分:3)

重要的是要注意扩展方法和常规方法之间存在差异。我认为你刚刚遇到其中一个。

我将举例说明另一个不同之处:在null对象引用上调用扩展方法相当容易。幸运的是,使用常规方法要困难得多。 (但它可以完成.IIRC,Jon Skeet通过操纵CIL代码演示了如何做到这一点。)

static void ExtensionMethod(this object obj) { ... }

object nullObj = null;
nullObj.ExtensionMethod();  // will succeed without a NullReferenceException!

话虽如此,我同意调用扩展方法需要this似乎有点不合逻辑。毕竟,扩展方法理想情况下应该“感觉”并且表现得像普通方法一样。

但实际上,扩展方法更像是在现有语言之上添加的语法糖,而不是早期的核心功能,它在所有方面都非常适合语言。

答案 4 :(得分:1)

因为ViewPage类不存在扩展方法。您需要告诉编译器您在调用扩展方法的内容。请记住,this.Method()只是ViewExtensions.Method(this)的编译糖。这与您不能通过方法名称在任何类的中间调用扩展方法的方式相同。

答案 5 :(得分:0)

我正在开发一个流畅的API并遇到了同样的问题。即使我可以访问I类扩展,我仍然希望每个流畅方法的逻辑都在他们自己的文件中。 &#34;这&#34;关键字非常不直观,用户一直认为该方法丢失了。我所做的是让我的类成为一个部分类,它实现了我需要的方法,而不是使用扩展方法。我没有在答案中提到部分内容。如果你有这个问题,部分可能是更好的选择。