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类的实例方法了吗?没有,编译器帮我们披了一层外衣, 把对“实例方法”的调用在编译时期改变成了静态类中的静态方法的调用,所以扩展方法是一种编译时技术。当扩展方法和实例方法签名相同时,实例方法优先使用。
作者:Blackheart
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。