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

M4N*_*M4N 75 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";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

<%: Method() %> <!-- gives error CS0103 -->
<%: this.Method() %> <!-- works -->
Run Code Online (Sandbox Code Playgroud)

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

(我认为这个问题肯定有重复,但我找不到一个)

更新:

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

Eri*_*ert 49

几点:

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

其次,功能的工作扩展方法更一般的设计:即,扩展方法允许你扩展类型,你不能扩展自己,可能是因为它是一个接口,你不知道实现,或者是因为你做知道实现,但没有源代码.

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

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

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

  • 谢谢你的回答!两点:1:我没有要求实现该功能,只是为了解释,为什么它不存在/为什么需要这个?2:为什么我从扩展类型调用扩展方法?在给出的示例中,我向基类(ViewPage)添加了一些便捷方法,并且我从派生类中调用它.这消除了为我的所有视图创建公共基类的需要.顺便说一句:我同意在扩展类型中使用扩展方法很尴尬,但再次看到MVC ViewPage的示例. (11认同)
  • 嗨,埃里克,授予这不是一个主要的情况.但是,一般模式似乎是1.您没有对基类的源编辑访问权限.2.您希望向基类型添加一些(受保护的)方法,您希望在派生类的主体中调用它们.是否有其他机制来实现这一目标?this.MethodName不是很难打字,但一段时间后它会变得很烦人...... (7认同)
  • 我认为将扩展方法添加到基类(你没有源代码)的场景是有效的.在那种情况下,能够在没有"this"的情况下调用方法会很棒.BTW这可以在下一个带有"静态导入"的c#版本中解决. (5认同)
  • 在您正在扩展的类中使用扩展方法的一个正当理由是,当您有多个类型实现接口时.例如,你有两个实现`ICrossProductable`的类,你在该接口上定义一个名为`GetProduct`的扩展方法.很简单的例子,但我经常觉得这很有用.尽管如此,这并不是最好的方法. (4认同)
  • @ M4N:这也是我的情况:我想扩展UserControl方法并将该扩展可用于我的所有UserControls,而没有明确的'this'.我知道编译器开发不是一个民主国家,但我认为这是一个隐含的'这个'的投票:-) (3认同)
  • *“如果您在该类型中使用扩展方法的场景中,那么您确实可以访问源代码......”* - 我会指出,例如,我可能想要添加“System.Object”的扩展方法(在我的例子中,以及我是如何找到这篇文章的,用于一个简单的事件聚合服务)。我希望 *每个* 对象都包含此方法,但我必须使用扩展方法才能这样做。在这种情况下,我不认为我正在违反此功能的预期用途。也就是说,使用 `this` 没什么大不了的,我很好,我只是很好奇。 (2认同)
  • @bmju:我鼓励您在 Roslyn github 论坛中向 C# 语言设计人员说明这种情况。我从 2012 年就没有在微软工作过。 (2认同)

Fer*_*cio 8

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

// without 'this'
string s = ViewExtensions.Method(page);
Run Code Online (Sandbox Code Playgroud)

// with 'this'
string s = page.Method();
Run Code Online (Sandbox Code Playgroud)


Ale*_*rey 6

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

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

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

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

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