[C#3] 1-扩展方法

时间:2022-04-23
本文章向大家介绍[C#3] 1-扩展方法,主要内容包括1.从DEMO开始、2.扩展方法剖析、3.总结、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

1.从DEMO开始

先看一个扩展方法的例子:

 1 class Program  
 2 {  
 3     public static void Main()  
 4     {  
 5         Int32 myNum = 1;  
 6         myNum = myNum.AddToOldNum(1);  
 7         Console.WriteLine(myNum);  
 8     }  
 9 }  
10       
11 public static class ExpandInt  
12 {  
13     //扩展方法必须为静态方法  
14         public static int AddToOldNum(this int oldNum,int newNum)  
15     {  
16         return oldNum + newNum;  
17     }  
18 }

为一个类型扩展一个方法如此只简单,但是它究竟为我们做了什么呢,为什么我可以调用的AddToOldNum方法?还是让我们从IL代码层面来看看吧。

2.扩展方法剖析

这里是上面代码编译的IL:

 1 .method public hidebysig static int32  AddToOldNum(
 2     int32 oldNum, int32 newNum) cil managed 
 3 { 
 4     .custom instance void [System.Core]
 5         System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )  
 6     // 代码大小       9 (0x9) 
 7     .maxstack  2 
 8     .locals init ([0] int32 CS$1$0000) 
 9     IL_0000:  nop 
10     IL_0001:  ldarg.0 
11     IL_0002:  ldarg.1 
12     IL_0003:  add 
13     IL_0004:  stloc.0 
14     IL_0005:  br.s       IL_0007 
15     IL_0007:  ldloc.0 
16     IL_0008:  ret 
17 } // end of method ExpandInt::AddToOldNum

发现它和一般的静态方法没什么区别,唯一不同的是多了一行调用[System.Runtime.CompilerServices.ExtensionAttribute]:

custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )  

MSDN告诉我System.Runtime.CompilerServices.ExtensionAttribute表明一个法是一种可拓方法, 或一个类或集合包含扩展方法【这里我也不太懂,嘿嘿】。从这个类型的结尾Extension_Attribute_就可看出它是一个特性类。 为我们的AddToOldNum方法添加了必要的元数据。

再来看看Main方法里发生了什么情况:

 1 .method public hidebysig static void  Main() cil managed 
 2 { 
 3     .entrypoint 
 4     // 代码大小       19 (0x13) 
 5     .maxstack  2 
 6     .locals init ([0] int32 myNum) 
 7     IL_0000:  nop 
 8     IL_0001:  ldc.i4.1 
 9     IL_0002:  stloc.0 
10     IL_0003:  ldloc.0 
11     IL_0004:  ldc.i4.1 
12     IL_0005:  call       int32 ConsoleApplication1.ExpandInt::AddToOldNum(
13                                                      int32, int32) 
14     IL_000a:  stloc.0 
15     IL_000b:  ldloc.0 
16     IL_000c:  call       void [mscorlib]System.Console::WriteLine(int32) 
17     IL_0011:  nop 
18     IL_0012:  ret 
19 } // end of method Program::Main

注意这一行,编译器把我们写的myNum = myNum.AddToOldNum(1)编译成这样:

IL_0005:  call  int32 ConsoleApplication1.ExpandInt::AddToOldNum(int32,int32)

"实例方法"的调用换成了ExpandInt::AddToOldNum(int32,int32)静态方法的调用,这就是扩展方法的本质所在了。

3.总结

我们真的扩展了Int32类的实例方法了吗?没有,编译器帮我们披了一层外衣, 把对“实例方法”的调用在编译时期改变成了静态类中的静态方法的调用,所以扩展方法是一种编译时技术。当扩展方法和实例方法签名相同时,实例方法优先使用。