简体   繁体   English

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

[英]Why is the 'this' keyword required to call an extension method from within the extended class

I have created an extension method for an ASP.NET MVC ViewPage, eg: 我已经为ASP.NET MVC ViewPage创建了一个扩展方法,例如:

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

When calling this method from a View (deriving from ViewPage ), I get the error " CS0103: The name 'Method' does not exist in the current context " unless I use the this keyword to call it: 从View(从ViewPage )调用此方法时,我收到错误“ CS0103:当前上下文中不存在名称'Method' ”,除非我使用this关键字来调用它:

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

Why is the this keyword required? 为什么需要this关键字? Or does it work without it, but I'm missing something? 或者没有它可以工作,但我错过了什么?

(I think there must be a duplicate of this question, but I was not able find one) (我认为这个问题肯定有重复,但我找不到一个)

Update : 更新

As Ben Robinson says , the syntax to call extension methods is just compiler sugar. 正如Ben Robinson所说 ,调用扩展方法的语法只是编译器糖。 Then why can't the compiler automatically check the for extension methods of the current type's base types without requiring the this keyword? 那为什么编译器不能自动检查当前类型的基类型的扩展方法而不需要this关键字?

A couple points: 几点:

First off, the proposed feature (implicit "this." on an extension method call) is unnecessary . 首先,建议的功能(在扩展方法调用上隐含“this。”)是不必要的 Extension methods were necessary for LINQ query comprehensions to work the way we wanted; LINQ查询理解需要扩展方法才能按照我们想要的方式工作; the receiver is always stated in the query so it is not necessary to support implicit this to make LINQ work. 接收器总是在查询中声明,因此没有必要支持隐式,以使LINQ工作。

Second, the feature works against the more general design of extension methods: namely, that extension methods allow you to extend a type that you cannot extend yourself , either because it is an interface and you don't know the implementation, or because you do know the implementation but do not have the source code. 其次,功能的工作扩展方法更一般的设计:即,扩展方法允许你扩展类型,你不能扩展自己 ,可能是因为它是一个接口,你不知道实现,或者是因为你做知道实现,但没有源代码。

If you are in the scenario where you are using an extension method for a type within that type then you do have access to the source code. 如果你是在场景中你使用的是扩展方法为该类型中的一个类型,那么你可以访问源代码。 Why are you using an extension method in the first place then? 为什么你首先使用扩展方法呢? You can write an instance method yourself if you have access to the source code of the extended type, and then you don't have to use an extension method at all! 如果您可以访问扩展类型的源代码,则可以自己编写实例方法 ,然后根本不必使用扩展方法! Your implementation can then take advantage of having access to the private state of the object, which extension methods cannot. 然后,您的实现可以利用对对象的私有状态的访问权限,而扩展方法则无法访问。

Making it easier to use extension methods from within a type that you have access to is encouraging the use of extension methods over instance methods. 在您有权访问的类型中更容易使用扩展方法,这鼓励在实例方法上使用扩展方法。 Extension methods are great, but it is usually better to use an instance method if you have one. 扩展方法很棒,但如果你有一个实例方法通常更好。

Given those two points, the burden no longer falls on the language designer to explain why the feature does not exist. 鉴于这两点,负担不再落在语言设计者解释为什么该功能存在。 It now falls on you to explain why it should . 它现在落在你身上,以解释为什么它应该 Features have enormous costs associated with them. 功能与它们相关的成本很高。 This feature is not necessary and works against the stated design goals of extension methods; 此功能不是必需的,并且违反了扩展方法的规定设计目标; why should we take on the cost of implementing it? 我们为什么要承担实施它的成本? Explain what compelling, important scenario is enabled by this feature and we'll consider implementing it in the future. 说明此功能启用了哪些引人注目的重要方案,我们将考虑将来实施它。 I don't see any compelling, important scenario that justifies it, but perhaps there is one that I've missed. 我没有看到任何令人信服的重要场景证明这一点,但也许有一个我错过了。

Without it the compiler just sees it as a static method in a static class which takes page as it's first parameter. 没有它,编译器只会将其视为静态类中的静态方法,该方法将页面作为第一个参数。 ie

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

vs.

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

On instance methods, 'this' is implicitly passed to each method transparently, so you can access all the members it provides. 在实例方法中,'this'以透明方式隐式传递给每个方法,因此您可以访问它提供的所有成员。

Extension methods are static. 扩展方法是静态的。 By calling Method() rather than this.Method() or Method(this) , you're not telling the compiler what to pass to the method. 通过调用Method()而不是this.Method()Method(this) ,您不会告诉编译器传递给方法的内容。

You might say 'why doesn't it just realise what the calling object is and pass that as a parameter?' 你可能会说'为什么它只是意识到调用对象是什么并将其作为参数传递?'

The answer is that extension methods are static and can be called from a static context, where there is no 'this'. 答案是扩展方法是静态的,可以从静态上下文中调用,其中没有“this”。

I guess they could check for that during compilation, but to be honest, it's probably a lot of work for extremely little payoff. 我猜他们可以在编译期间检查一下,但说实话,这可能是非常少的回报。 And to be honest, I see little benefit in taking away some of the explicitness of extension method calls. 说实话,我认为在取消一些扩展方法调用的显式方面没什么好处。 The fact that they can be mistaken for instance methods means that they can be quite unintuitive at times (NullReferenceExceptions not being thrown for example). 事实上,它们可能被误认为是方法,这意味着它们有时可能非常不直观(例如,不会抛出NullReferenceExceptions)。 I sometimes think that they should have introduced a new 'pipe-forward' style operator for extension methods. 我有时认为他们应该为扩展方法引入一个新的“管道前移”式操作符。

It's important to note that there are differences between extension methods and regular methods. 重要的是要注意扩展方法和常规方法之间存在差异。 I think you've just come across one of them. 我想你刚刚碰到其中一个。

I'll give you an example of another difference: It's fairly easy to call an extension method on a null object reference. 我将举例说明另一个不同之处:在null对象引用上调用扩展方法相当容易。 Fortunately, this is much more difficult to do with regular methods. 幸运的是,使用常规方法要困难得多。 (But it can be done. IIRC, Jon Skeet demonstrated how to do this by manipulating CIL code.) (但它可以完成.IIRC,Jon Skeet通过操纵CIL代码演示了如何做到这一点。)

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

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

That being said, I agree that it seems a little unlogical that this is required to call the extension method. 话虽如此,我同意this需要调用扩展方法似乎有点不合逻辑。 After all, an extension method should ideally "feel" and behave just like a normal one. 毕竟,扩展方法应该理想地“感觉”并且表现得像普通方法一样。

But in reality, extension methods are more like syntactic sugar added on top of the existing language than an early core feature that fits nicely into the language in all respects. 但实际上,扩展方法更像是在现有语言之上添加的语法糖,而不是早期的核心功能,它在所有方面都非常适合语言。

Because the extension method does not exist with the ViewPage class. 因为ViewPage类不存在扩展方法。 You need to tell the compiler what you are calling the extension method on. 您需要告诉编译器您在调用扩展方法的内容。 Remember this.Method() is just compiler sugar for ViewExtensions.Method(this) . 记住this.Method()只是ViewExtensions.Method(this)编译器糖。 It is the same way you can't just call an extention method within the middle of any class by the method name. 这与您不能通过方法名称在任何类的中间调用扩展方法的方式相同。

I am working on a fluent API and ran into the same issue. 我正在研究一个流畅的API并遇到了同样的问题。 Even though I have access to the class I'm extending I still wanted the logic of each of the fluent methods to be in their own files. 即使我可以访问我正在扩展的类,我仍然希望每个流畅方法的逻辑都在他们自己的文件中。 The "this" keyword was very unintuitive, users kept thinking the method was missing. “this”关键字非常不直观,用户一直认为该方法丢失了。 What I did was make my class a partial class that implemented the methods I needed instead of using extension methods. 我所做的是让我的类成为一个部分类,它实现了我需要的方法,而不是使用扩展方法。 I saw no mention of partials in the answers. 我没有在答案中提到部分内容。 If you have this question partials might be a better option. 如果您有这个问题,部分可能是更好的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM