Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 扩展方法如何连接_C#_.net - Fatal编程技术网

C# 扩展方法如何连接

C# 扩展方法如何连接,c#,.net,C#,.net,我只是想知道扩展方法是如何连接到原始类的。我知道在IL代码中它调用了静态方法,但它是如何做到的,为什么不破坏封装的。它们没有“连接” Visaul Studio IDE只是通过在intellisense列表中显示它们使其看起来像是这样 编译器“知道”如何处理引用,以便使用正确的参数进行正确的方法调用 这很简单-这些方法只是单独静态类上的静态方法。使用修饰符可以让编译器“知道”将添加到类中以将其标记为扩展方法 由于扩展方法实际上不会更改类,并且只能访问类上的公共成员,因此保留了封装 发件人: 扩展

我只是想知道扩展方法是如何连接到原始类的。我知道在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...
}