.NET3.5 发展的背后(2)扩展方法

今天我接着给大家演绎一下.net3.5的新特性.那就是扩展方法(extention method),这个也是比较有意思的.你可以使用实例方法的语法来调用静态方法,你可以不把要扩展的方法加到代码里就可以对这个类进行扩展,这个对买别人dll用的,或者说是相对某编译好的类在扩展一下提供了可能.
当然我们一定要看看它们背后卖的是什么药?
首先介绍一下扩展方法声明
扩展方法的行为和静态方法是非常类似的,你只能在静态类中声明它们。为声明一个扩展方法,你需要给该方法的第一个参数指定this关键字
例如:
首先定义一个汽车类,它具有Speed一个公共字段来提供它的速度
    class Car
    
{
        
public int Speed;
        
public int SpeedUp()
        
{
            
return ++Speed;
        }

    }
接下来呢,我们为它提供一个静态类中的静态方法(多嘴一句,扩展方法只能定义在静态类的静态方法中).顺便也写上个一普通的静态方法来作比较
    static class ExtensionMethodsClass
    
{
        
public static int SpeedDown(this Car c)
        
{
            
return --c.Speed;
        }


        
public static void SpeedUp(Car car)
        
{
            car.Speed
++;
        }

    }
那我们就要测试一下我们的扩展方法了.
        static void Main(string[] args)
        
{

            Car car 
= new Car();
            car.SpeedUp();
            Console.WriteLine(car.Speed.ToString());
            car.SpeedDown();
            Console.WriteLine(car.Speed.ToString());
            ExtensionMethodsClass.SpeedUp(car);
            Console.WriteLine(car.Speed.ToString());
            Console.ReadLine();
        }
编译,运行,接着看看结果,结果是什么并不重要,重要的就是我们要看看它们背后作了些什么.找出我们的法宝ildasm工具来,把你刚才的编译好的exe文件拽进去.
我们来比较着三个方法的il代码,看看里面到底发生了些什么!
首先呢看Car类中的SpeedUp()方法的il代码
 1.method public hidebysig instance int32  SpeedUp() cil managed
 2{
 3  // Code size       23 (0x17)
 4  .maxstack  3
 5  .locals init ([0] int32 CS$1$0000,
 6           [1] int32 CS$0$0001)
 7  IL_0000:  nop
 8  IL_0001:  ldarg.0
 9  IL_0002:  dup
10  IL_0003:  ldfld      int32 HelloLinq.Car::Speed
11  IL_0008:  ldc.i4.1
12  IL_0009:  add
13  IL_000a:  dup
14  IL_000b:  stloc.1
15  IL_000c:  stfld      int32 HelloLinq.Car::Speed
16  IL_0011:  ldloc.1
17  IL_0012:  stloc.0
18  IL_0013:  br.s       IL_0015
19  IL_0015:  ldloc.0
20  IL_0016:  ret
21}
 // end of method Car::SpeedUp
22
23
接着看ExtensionMethodsClass类中的SpeedDown()方法
 1.method public hidebysig static int32  SpeedDown(class HelloLinq.Car c) cil managed
 2{
 3  .custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ) 
 4  // Code size       23 (0x17)
 5  .maxstack  3
 6  .locals init ([0] int32 CS$1$0000,
 7           [1] int32 CS$0$0001)
 8  IL_0000:  nop
 9  IL_0001:  ldarg.0
10  IL_0002:  dup
11  IL_0003:  ldfld      int32 HelloLinq.Car::Speed
12  IL_0008:  ldc.i4.1
13  IL_0009:  sub
14  IL_000a:  dup
15  IL_000b:  stloc.1
16  IL_000c:  stfld      int32 HelloLinq.Car::Speed
17  IL_0011:  ldloc.1
18  IL_0012:  stloc.0
19  IL_0013:  br.s       IL_0015
20  IL_0015:  ldloc.0
21  IL_0016:  ret
22}
 // end of method ExtensionMethodsClass::SpeedDown
23
24
朋友们看累了吧,在忍一忍,看最后一个ExtensionMethodsClass类中的SpeedUp()方法
 1.method public hidebysig static void  SpeedUp(class HelloLinq.Car car) cil managed
 2{
 3  // Code size       16 (0x10)
 4  .maxstack  8
 5  IL_0000:  nop
 6  IL_0001:  ldarg.0
 7  IL_0002:  dup
 8  IL_0003:  ldfld      int32 HelloLinq.Car::Speed
 9  IL_0008:  ldc.i4.1
10  IL_0009:  add
11  IL_000a:  stfld      int32 HelloLinq.Car::Speed
12  IL_000f:  ret
13}
 // end of method ExtensionMethodsClass::SpeedUp
14
15

朋友们,看到了这其中的奥秘了吧,第一个方法就是一个普通的实例方法,第三个方法呢就是一个普通的静态方法,这最特别的就是我们的第二个了,也就是我们的扩展方法,它特别在
.custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
这句话翻译成普通话的意思就是告诉编译器我这个方法只能用在实例方法上,具体那个实例呢,由入口参数来决定的.

这个特性不错吧,一个字好.但是在好也不能滥用,就像医院治病打强心针似的,好,的确治病.但是不能因为能治病就给每一个病人都打.滥用是错误地,就像这打强心针一样不到非用不可的地步我认为还是不用为好,很容易就被滥用.那这么说吧,你找到用这个东西的合适的理由那你就放心的用吧!
原文地址:https://www.cnblogs.com/cuiweifu/p/1087928.html