转载

【备战面试之】四、谈扩展方法的理解

为什么要用扩展方法

在说什么是扩展方法之前我们先来说说为什么要用扩展方法。

首先我们定义一个 Person 类:

 public class Person {     /// <summary>     /// 出生日期     /// </summary>     public DateTime BirthTime { get; set; }     /// <summary>     /// 死亡日期     /// </summary>     public DateTime? DeathTime { get; set; }     //、、、、、、 } 

加入这个类来自第三方的dll引用,且现在我们需要添加一个方法 GetAge 获取年龄。你可能会想到自己定一个子类继承:

 public class MyPerson : Person {     public int GetAge()     {         if (DeathTime.HasValue)             return (DeathTime.Value - BirthTime).Days / 365;         else             return (DateTime.Now - BirthTime).Days / 365;     } } 

是的,这样可以实现我们的需求。不过实现新增的方法就去继承真的是最合适的吗( 暂且不说 )? 如果上面定义的密封类呢?  public sealed class Person ,这个时候是不能继承的,我们只能另想办法。

随意写个静态类:

 public static class ExtensionClass {     public static int GetAge(Person person)     {         if (person.DeathTime.HasValue)             return (person.DeathTime.Value - person.BirthTime).Days / 365;         else             return (DateTime.Now - person.BirthTime).Days / 365;     } 

然后调用 age = ExtensionClass.GetAge(p); ,是的看似不错。可是这和我们说的扩展方法有什么关系呢?下面就是见证奇迹的时候了。

【备战面试之】四、谈扩展方法的理解

其他的任何地方都不变,唯一变化的是在参数前面加里this关键字。对,是的,仅仅如此它就变成了我们今天要讲的扩展方法。

调用如: var age = p.GetAge(); 相比上面的  age = ExtensionClass.GetAge(p); 更简单明了。

这里我们说的是在需要扩展密封类的方法时,我们可以使用到扩展方法。还有一种情况就是,在需要扩展接口的时候时候我们更加需要。比如,需要扩展IList的排序。我们要么写个扩展方法,要么是继承实现接口( 会强制要求实现接口下的所有方法 )。我想你心中已经有了答案选择哪种方式。

扩展方法到底是什么

我们看到上面使用的扩展方法,有没有感觉很神奇。仅仅多添加了一个this关键字就直接可以当成扩展方法使用了。那扩展方法到底是什么东东,看了上面代码好像和静态方法有着说不清道不明的关系。下面我们继续分析:

  public static class ExtensionClass  {      public static int GetAge2(Person person)      {          if (person.DeathTime.HasValue)              return (person.DeathTime.Value - person.BirthTime).Days / 365;          else              return (DateTime.Now - person.BirthTime).Days / 365;      }       public static int GetAge(this Person person)      {          if (person.DeathTime.HasValue)              return (person.DeathTime.Value - person.BirthTime).Days / 365;          else              return (DateTime.Now - person.BirthTime).Days / 365;      } 

分别定义一个静态方法和一个扩展方法

 var p = new Person() { BirthTime = DateTime.Parse("1990-07-19") }; var age = p.GetAge(); age = ExtensionClass.GetAge2(p); 

分别调用。

【备战面试之】四、谈扩展方法的理解

我们看到反编译成IL之后发现两者并无不同。所以,我理解成( 扩展方法本质上就是静态方法,之所以出现扩展方法是C#以另外一种形式表现静态方法而已。只有有何妙用下面会继续讲解 )。且  【备战面试之】四、谈扩展方法的理解 编译后 【备战面试之】四、谈扩展方法的理解 同样带上了静态类名。

扩展方法可以做些什么

  • 把已有的静态方法转成扩展方法:如:
 public static bool IsNullOrEmpty(this string str) {     return string.IsNullOrEmpty(str); } 

调用:

 string str = null; var isNull = str.IsNullOrEmpty(); 

感觉相比期静态方法调用要优雅,更接近我们的自然语言。

  •  可以编写很多的帮助类,如( 以string为例 ):
  /// <summary>         /// 转DateTime          /// </summary>         /// <param name="str"></param>         /// <returns></returns>         public static DateTime? MyToDateTime(this string str)         {             if (string.IsNullOrEmpty(str))                 return null;             else                 return DateTime.Parse(str);         }          /// <summary>         /// 转double         /// </summary>         /// <param name="str"></param>         /// <returns></returns>         public static double MyToDouble(this string str)         {             if (string.IsNullOrEmpty(str))                 return -1;             else                 return double.Parse(str);         }          /// <summary>         /// 转int         /// </summary>         /// <param name="str"></param>         /// <returns></returns>         public static int MyToInt(this string str)         {             if (string.IsNullOrEmpty(str))                 return -1;             else                 return int.Parse(str);         }          /// <summary>         /// 指示指定的字符串是 null 还是 System.String.Empty 字符串。         /// </summary>         /// <param name="str"></param>         /// <returns></returns>         public static bool IsNullOrEmpty(this string str)         {             return string.IsNullOrEmpty(str);         }          /// <summary>         /// 如果字符串为null,则返回空字符串。(否则返回原字符串)         /// </summary>         /// <param name="str"></param>         /// <returns></returns>         public static string GetValueOrEmpty(this string str)         {             if (str.IsNullOrEmpty())                 return string.Empty;             return str;         }  View Code

上面所有的都只是扩展方法的附加用处,扩展方法真正的威力是为Linq服务的( 主要体现于IEnumerable和IQueryable ),实现链式编程。下面我们自己来实现所谓的链式编程:

初始化 Person 集合。

 List<Person> persons = new List<Person>()  {      new Person(){ BirthTime=DateTime.Parse("1990-01-19")},      new Person(){ BirthTime=DateTime.Parse("1993-04-17")},      new Person(){ BirthTime=DateTime.Parse("1992-07-19"), DeathTime=DateTime.Parse("2010-08-18")},      new Person(){ BirthTime=DateTime.Parse("1990-03-14")},      new Person(){ BirthTime=DateTime.Parse("1991-08-15")},      new Person(){ BirthTime=DateTime.Parse("1993-07-29")},      new Person(){ BirthTime=DateTime.Parse("1991-06-19")} }; 

需求:1.查询活人。2.按出生日期排序

 public static class ExtensionClass     {         /// <summary>         /// 按条件查询         /// </summary>         /// <typeparam name="T"></typeparam>         /// <param name="list"></param>         /// <param name="func"></param>         /// <returns></returns>         public static IList<T> MyWhere<T>(this IList<T> list, Func<T, bool> func)         {             List<T> newList = new List<T>();             foreach (var item in list)             {                 if (func(item))                     newList.Add(item);             }             return newList;         }          /// <summary>         /// 升序排序         /// </summary>         /// <typeparam name="T"></typeparam>         /// <param name="list"></param>         /// <param name="func"></param>         /// <returns></returns>         public static IList<T> MyOrderBy<T>(this IList<T> list, Func<T, DateTime> func)         {             if (list.Count() <= 1)                 return list;              for (int i = 0; i < list.Count(); i++)             {                 for (int j = i + 1; j < list.Count(); j++)                 {                     var item1 = list[j - 1];                     var item2 = list[j];                     if ((func(item1) - func(item2)).Ticks > 0)                     {                         list[j - 1] = item2;                         list[j] = item1;                     }                 }             }             return list;         }         /// <summary>         /// 降序排序         /// </summary>         /// <typeparam name="T"></typeparam>         /// <param name="list"></param>         /// <param name="func"></param>         /// <returns></returns>         public static IList<T> MyOrderByDescending<T>(this IList<T> list, Func<T, DateTime> func)         {             if (list.Count() <= 1)                 return list;              for (int i = 0; i < list.Count(); i++)             {                 for (int j = 1; j < list.Count() - i; j++)                 {                     var item1 = list[j - 1];                     var item2 = list[j];                     if ((func(item1) - func(item2)).Ticks < 0)                     {                         list[j - 1] = item2;                         list[j] = item1;                     }                 }             }             return list;         }     } 

调用:( 这里仅仅为了演示,所以不要讨论实现是否合理、算法是否高效。

 var newPersons = persons.MyWhere(t => t.DeathTime == null).MyOrderByDescending(t => t.BirthTime); foreach (var item in newPersons) {     Console.WriteLine(item.BirthTime); } 

就是如此简单的实现了所谓的函数式编程。结果图如下:

【备战面试之】四、谈扩展方法的理解

这样一句代码搞定所有逻辑,像自然语言般的流畅。其实.net为IEnumerable实现了这样的扩展,如:

【备战面试之】四、谈扩展方法的理解

执行结构和上面一模一样。

以上都是胡说八道。

好了,今天的扩展方法就分析到这里。感谢阅读,希望对您有一点点作用!

文章首链: http://www.cnblogs.com/zhaopei/p/5678842.html

原文  http://www.haojima.net/zhaopei/568.html
正文到此结束
Loading...