c#3.0系列:Extension Method
我们说在C#3.0中,引入了一些列新的特性,但是个人认为Extension Method这个特性是最爽的,最有创新的。
它真正的解决了:在保持现有Type原封不动的情况下对其进行扩展,你可以在对Type的定义不做任何变动的情况下,为之添加所需的方法成员。下面我就来讲讲。
C#3.X出来之前
大家都知道javascript有个特新Prototype,它就如同C#3.X中的Extension Method。这里不多将了。
我们主要看看.NET的实现。在C#3.X出来之前我们可以做到对Type进行扩展。
interface的情况:

2

3

4

5

6

对这个Interface进行扩展,为之添加一个Add方法执行相关的运算。我们唯一的解决方案就是直接在这个Interface中添加一个Add成员。如上。实现了这个Interface的Type必须实现该Interface的所有方法。所以,我们添加了Add这个方法,将导致所有实现它的Type的重新定义和编译,在很多情况下,我们根本不需要这样。
Class的情况:
如果我们将一个class作为基类,在基类中添加一个Add Method,所有的Child Class都不会受到影响。但是在很多情况下,对于我们需要扩展的Interface或者是class,我们是完全不能做任何改动。比如,我们要对datagrid控件进行扩展。我们常用的方法就自定义一个Class去继承这个datagrid,将需要添加的成员定义在我们自己定义的Class中,这就是我们常说的自定义控件,如果对于一个Sealed Class又该如何呢?我们要求的是对这个不能变动的Type进行扩展,也就是使这个不能变动的Type的Instance具有我们添加的对象。
如果听到这样的要求:我们要对一个Type或者Interface进行扩展,却不允许我们修改它。这个要求确实有点苛刻。但是c#3.x 中我们可以选择Extension Method。Extension Method本质上是在被扩展的对象实例上可以调用的静态函数,不是继承,所以不同于普通的成员函数,扩展函数不能直接访问被扩展对象的成员。只能通过该对象的实例来访问。
C#3.X出来之后
简单地说Extension Method是一个定义在Static Class的一个特殊的Static Method。之所以说这个Static Method特别,是因为Extension Method不但能按照Static Method的语法进行调用,还能按照Instance Method的语法进行调用。
我们还是先来看例子:
















我们可以看看上面的例子,我们知道net framework 里string是个Sealed 类型,我们只能使用Extension Method来对其进行扩展。我们可以看看它的定义方式。ToInt32是一个Static方法。和一般的Static方法不同的是:在第一个参数前添加了一个this 关键字。这是在C# 3.0中定义Extension Method而引入的关键字。添加了这样一个关键字就意味着在调用该方法的时候这个标记有this的参数可以前置,从而允许我们向调用一般Instance Method的方式来调用这个Static Method。注意:需要在(只需要在)第一个参数前面使用this修饰。
Extension Method IN CLR
C# 3.0的这些新的特性大都影响Source被C# Compiler编译成Assembly这个阶段,换句话说,这些新特仅仅是Compiler的新特性而已。通过对Compiler进行修正,促使他将C# 3.0引入的新的语法编译成相对应的IL Code,从本质上看,这些IL Code 和原来的IL并没有本质的区别。所有当被编译生成成Assembly被CLR加载、执行的时候,CLR是意识不到这些新的特性的。
我们先看看Extension Method与传统的Static Method有什么区别。

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

大家注意,这是Extension Method的IL,它与传统的Static Method最大的区别事在Extension Method多了这句:
.custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor()
就是在ToInt32方法上添加一个Customer Attribute:System.Runtime.CompilerServices.ExtensionAttribute。这个
属性是为了Extension Method的而定义的。
我们再来看看,IL事如何实现Instance Method方式调用Extension Method的。

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

通过上面的IL,我们看到调用的是ConsoleApplication1.MyExtensionMethods的ToInt32方法。
我们基本上看出了Extension Method的本质。当Compiler对Adds方法的调用进行编译的过程的时候,它必须判断这个ToInt32方式是String已有的成员还是以Extension Method的方式定义。Extension Method的优先级是最低的,只有确定String中没有定义相应的ToInt32方法的时候,Compiler才会在引用的Namespace中查看这些Namespace中是否定义有对应的ToInt32 Extension Method的Static Class。找到后作进行相应的编译,否则出现编译错误。
扩展接口类型
看下面的例子

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

注意这里扩展时必须给出函数的实现,扩展接口后,显然不能直接在接口上调用这些扩展函数,只能理解为,所有继承该接口的对象新增加了这些扩展函数功能。
注意事项:
引用扩展函数
必须引用定义扩展函数的命名空间,否则扩展函数不可用。
智能提示
Visual studio 的智能提示将扩展函数标记为向下的蓝色箭头。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述