不论是JavaScript还是C#程序,我们已经习惯了采用如下所示的“链式调用”的方式进行编程,这样确实会使我们的程序变得很精练。


   1: new Foo()

   2:     .UseXxx()

   3:     .UseZzz()

   4:     .UseZzz()

   5:     .Invoke();


采用这种链式调用方式的很多方法都是扩展方法,比如上面所示的UseXxx、UseYyy和UseXxx方法就是采用如下形式定义的扩展方法。


   1: public interface IFoo

   2: {

   3:     void Invoke();

   4: }

   5:  

   6: public class Foo : IFoo

   7: {

   8:     public void Invoke()

   9:     {}

  10:     public void Execute()

  11:     {}

  12: }

  13:  

  14: public static class FooExtensions

  15: {

  16:     public static IFoo UseXxx(this IFoo foo)

  17:     {

  18:         return foo;

  19:     }

  20:     public static IFoo UseYyy(this IFoo foo)

  21:     {

  22:         return foo;

  23:     }

  24:     public static IFoo UseZzz(this IFoo foo)

  25:     {

  26:         return foo;

  27:     }

  28: }


到目前为止,一切都显得很完美,而且我看到绝大部分的扩展方法也是采用这种方式定义的。但是如果我们希望采用如下的方式调用Foo的Execute方法的,很明显下面这样的代码是不能通过编译的。


   1: new Foo()

   2:     .UseXxx()

   3:     .UseZzz()

   4:     .UseZzz()

   5:     .Execute();


我们不得不将这段代码改写成如下的形式。改写的代码显得很丑陋,和上面这段代码相比较:

  • 第一、多声明了一个变量;

  • 第二、将一段很“流畅”的代码活生生拆分成两段;

  • 第三、在调用Execute方法是添加了一个很“生硬”的类型转换。


   1: IFoo foo = new Foo()

   2:     .UseXxx()

   3:     .UseYyy()

   4:     .UseZzz();

   5:  

   6: ((Foo)foo).Execute();


如果希望上面这段代码合法有效,我们的三个扩展方法应该定一个成如下的形式。


   1: public static class FooExtensions

   2: {

   3:     public static T UseXxx<T>(this T foo) where T: IFoo

   4:     {

   5:         return foo;

   6:     }

   7:     public static T UseYyy<T>(this T foo) where T : IFoo

   8:     {

   9:         return foo;

  10:     }

  11:     public static T UseZzz<T>(this T foo) where T : IFoo

  12:     {

  13:         return foo;

  14:     }

  15: }


https://mp.weixin.qq.com/s/6x7xxKWG11OxMp0HzuMvvA