简体   繁体   English

扩展方法如何挂钩

[英]How extension methods hook up

I was just curious to know how Extension methods are hooked up to the Original class. 我只是想知道如何将Extension方法连接到Original类。 I know in IL code it gives a call to Static Method, but how it does that and why dosen't it break encapsulation. 我知道在IL代码中它调用了静态方法,但它是如何做到的,为什么不打破封装。

They don't "hook up". 他们没有“勾结”。

The Visaul Studio IDE just makes it look like it does by showing them in the intellisense lists. Visaul Studio IDE只是通过在intellisense列表中显示它们来使它看起来像它。

The compiler "knows" how to deal with the references in order to make the right method calls with the correct parameters. 编译器“知道”如何处理引用,以便使用正确的参数进行正确的方法调用。

This is simply syntactic sugar - the methods are simply static methods on a separate static class. 这只是语法糖 - 这些方法只是一个单独的静态类上的静态方法。 Using the this modifier lets the compiler "know" to add the ExtensionAttribute to the class to mark it as an extension method. 使用this修饰符可让编译器“知道”将ExtensionAttribute添加到类中以将其标记为扩展方法。

Since extension methods do not in fact change the class and can only access public members on it, encapsulation is retained. 由于扩展方法实际上不会 更改类并且只能访问其上的公共成员,因此保留了封装。

From MSDN : 来自MSDN

Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. 扩展方法是一种特殊的静态方法,但他们被称为好像他们是在扩展类型实例的方法。

(emphasis mine) (强调我的)

Extension methods are specified by putting the this keyword in front of the first parameter of a static method: 通过将this关键字放在静态方法的第一个参数前面来指定扩展方法:

public static void SomeExtension(this string s)
{
    ...
}

That is just syntactic sugar for decorating the method with System.Runtime.CompilerServices.ExtensionAttribute : 这只是用System.Runtime.CompilerServices.ExtensionAttribute修饰方法的语法糖:

[Extension]
public static void SomeExtension(string s)
{
    ...
}

When the compiler sees that attribute, it knows to translate the extension method call to the appropriate static method call, passing the instance as the first parameter. 当编译器看到该属性时,它知道将扩展方法调用转换为适当的静态方法调用,并将该实例作为第一个参数传递。

Since the calls are just normal static method calls, there is no chance to break encapsulation; 由于调用只是普通的静态方法调用,因此没有机会破坏封装; the methods, like all static methods, only have access to the public interfaces of the extended types. 与所有静态方法一样,这些方法只能访问扩展类型的公共接口。

Extension methods are just syntactic sugar, they are just static methods. 扩展方法只是语法糖,它们只是静态方法。 You are only able to access public fields or properties in them, just like normal static methods. 您只能访问公共字段或属性,就像普通的静态方法一样。

The key ingredient is that an instance method of a class isn't fundamentally different from a static method. 关键因素是类的实例方法与静态方法没有根本的区别。 With one small detail, they have a hidden argument. 有一个小细节,他们有一个隐藏的论点。 For example, the String.IndexOf(char) method actually looks like this to the CLR: 例如,String.IndexOf(char)方法实际上看起来像CLR:

public static int IndexOf(string thisRef, char value) {
   // etc...
}

The thisRef argument is what supplies the string reference whenever you use this in your code or access a member of the class. thisRef参数是在代码中使用或访问类的成员时提供字符串引用的内容。 As you can see, it is a very small step from an extension method to an instance method. 正如你所看到的,它是一个扩展方法一个非常小的一步一个实例方法。 No changes were necessary in the CLR to support the feature. CLR中无需进行任何更改即可支持该功能。

One other minor difference is that the compiler emits code that checks if this is null for an instance method but does not do so for an extension method. 另外一个微小的差别是,编译器发出来检查,如果是空的实例方法,但是对于扩展方法没有这样做的代码。 You can call an extension method on a null object. 您可以在null对象上调用扩展方法。 While that might look like a feature, it is actually a restriction induced by the extension method not actually being a member of the class. 虽然这可能看起来像一个特征,但它实际上是由扩展方法引起的限制,实际上并不是该类的成员。

Internally, the CLR keeps a list of methods for the class, the MethodTable. 在内部,CLR保留了类的方法列表,即MethodTable。 Extension methods are not in them, preventing the compiler from emitting the callvirt IL instruction, the 'trick' that it uses to get the cheap null check. 扩展方法不在其中,阻止编译器发出callvirt IL指令,它是用来获得廉价空值检查的“技巧”。 Explicitly emitting code to make the null check would have been possible but they elected not to do so. 显式发出代码以进行空检查是可能的,但他们选择不这样做。 Not quite sure why. 不太清楚为什么。

Another automatic consequence of this is that an extension method cannot be virtual. 另一个自动结果是扩展方法不能是虚拟的。

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

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