C# 扩展方法如何连接
我只是想知道扩展方法是如何连接到原始类的。我知道在IL代码中它调用了静态方法,但它是如何做到的,为什么不破坏封装的。它们没有“连接” Visaul Studio IDE只是通过在intellisense列表中显示它们使其看起来像是这样 编译器“知道”如何处理引用,以便使用正确的参数进行正确的方法调用 这很简单-这些方法只是单独静态类上的静态方法。使用修饰符可以让编译器“知道”将添加到类中以将其标记为扩展方法 由于扩展方法实际上不会更改类,并且只能访问类上的公共成员,因此保留了封装 发件人: 扩展方法是一种特殊的静态方法,但它们被称为,就好像它们是扩展类型上的实例方法一样C# 扩展方法如何连接,c#,.net,C#,.net,我只是想知道扩展方法是如何连接到原始类的。我知道在IL代码中它调用了静态方法,但它是如何做到的,为什么不破坏封装的。它们没有“连接” Visaul Studio IDE只是通过在intellisense列表中显示它们使其看起来像是这样 编译器“知道”如何处理引用,以便使用正确的参数进行正确的方法调用 这很简单-这些方法只是单独静态类上的静态方法。使用修饰符可以让编译器“知道”将添加到类中以将其标记为扩展方法 由于扩展方法实际上不会更改类,并且只能访问类上的公共成员,因此保留了封装 发件人: 扩展
(我的重点)扩展方法只是语法糖,它们只是静态方法。与普通静态方法一样,您只能访问其中的公共字段或属性。扩展方法是通过将
this
关键字放在静态方法的第一个参数前面来指定的:
public static void SomeExtension(this string s)
{
...
}
这只是用以下语法修饰方法:
当编译器看到该属性时,它知道将扩展方法调用转换为适当的静态方法调用,并将实例作为第一个参数传递
因为调用只是普通的静态方法调用,所以没有机会破坏封装;与所有静态方法一样,这些方法只能访问扩展类型的公共接口。关键因素是类的实例方法与静态方法没有本质上的区别。有一个小细节,他们有一个隐藏的论点。例如,String.IndexOf(char)方法在CLR中实际上是这样的:
public static int IndexOf(string thisRef, char value) {
// etc...
}
thisRef参数是在代码中使用该参数或访问类成员时提供字符串引用的参数。正如您所看到的,从扩展方法到实例方法只是一小步。无需在CLR中进行任何更改即可支持该功能
另一个微小的区别是编译器发出的代码检查实例方法是否为null,而扩展方法则不这样做。可以对空对象调用扩展方法。虽然这看起来像是一个特性,但实际上是由扩展方法引起的限制,而扩展方法实际上不是类的成员
在内部,CLR为类MethodTable保留一个方法列表。扩展方法不在其中,这会阻止编译器发出callvirt-IL指令,这是它用来获得廉价空检查的“技巧”。显式地发出代码进行空检查本来是可能的,但他们选择不这样做。不太清楚为什么
这样做的另一个自动后果是扩展方法不能是虚拟的。我认为您应该看看
public static int IndexOf(string thisRef, char value) {
// etc...
}