【转】五、谈扩展方法的理解
【轉(zhuǎn)】五、談擴(kuò)展方法的理解
為什么要用擴(kuò)展方法
在說什么是擴(kuò)展方法之前我們先來說說為什么要用擴(kuò)展方法。
首先我們定義一個(gè)?Person?類:
public class Person {/// <summary>/// 出生日期/// </summary>public DateTime BirthTime { get; set; }/// <summary>/// 死亡日期/// </summary>public DateTime? DeathTime { get; set; }//、、、、、、 }加入這個(gè)類來自第三方的dll引用,且現(xiàn)在我們需要添加一個(gè)方法?GetAge?獲取年齡。你可能會想到自己定一個(gè)子類繼承:
public class MyPerson : Person {public int GetAge(){if (DeathTime.HasValue)return (DeathTime.Value - BirthTime).Days / 365;elsereturn (DateTime.Now - BirthTime).Days / 365;} }是的,這樣可以實(shí)現(xiàn)我們的需求。不過實(shí)現(xiàn)新增的方法就去繼承真的是最合適的嗎(暫且不說)??如果上面定義的密封類呢??public sealed class Person?,這個(gè)時(shí)候是不能繼承的,我們只能另想辦法。
隨意寫個(gè)靜態(tài)類:
public static class ExtensionClass {public static int GetAge(Person person){if (person.DeathTime.HasValue)return (person.DeathTime.Value - person.BirthTime).Days / 365;elsereturn (DateTime.Now - person.BirthTime).Days / 365;}然后調(diào)用? age = ExtensionClass.GetAge(p);?,是的看似不錯(cuò)。可是這和我們說的擴(kuò)展方法有什么關(guān)系呢?下面就是見證奇跡的時(shí)候了。
其他的任何地方都不變,唯一變化的是在參數(shù)前面加里this關(guān)鍵字。對,是的,僅僅如此它就變成了我們今天要講的擴(kuò)展方法。
調(diào)用如:? var age = p.GetAge();?相比上面的?age = ExtensionClass.GetAge(p);?更簡單明了。
這里我們說的是在需要擴(kuò)展密封類的方法時(shí),我們可以使用到擴(kuò)展方法。還有一種情況就是,在需要擴(kuò)展接口的時(shí)候時(shí)候我們更加需要。比如,需要擴(kuò)展IList的排序。我們要么寫個(gè)擴(kuò)展方法,要么是繼承實(shí)現(xiàn)接口(會強(qiáng)制要求實(shí)現(xiàn)接口下的所有方法)。我想你心中已經(jīng)有了答案選擇哪種方式。
擴(kuò)展方法到底是什么
我們看到上面使用的擴(kuò)展方法,有沒有感覺很神奇。僅僅多添加了一個(gè)this關(guān)鍵字就直接可以當(dāng)成擴(kuò)展方法使用了。那擴(kuò)展方法到底是什么東東,看了上面代碼好像和靜態(tài)方法有著說不清道不明的關(guān)系。下面我們繼續(xù)分析:
分別定義一個(gè)靜態(tài)方法和一個(gè)擴(kuò)展方法
public static class ExtensionClass{public static int GetAge2(Person person){if (person.DeathTime.HasValue)return (person.DeathTime.Value - person.BirthTime).Days / 365;elsereturn (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;elsereturn (DateTime.Now - person.BirthTime).Days / 365;}分別調(diào)用:
var p = new Person() { BirthTime = DateTime.Parse("1990-07-19") }; var age = p.GetAge(); age = ExtensionClass.GetAge2(p);編譯后的IL代碼:
我們看到反編譯成IL之后發(fā)現(xiàn)兩者并無不同。所以,我理解成(擴(kuò)展方法本質(zhì)上就是靜態(tài)方法,之所以出現(xiàn)擴(kuò)展方法是C#以另外一種形式表現(xiàn)靜態(tài)方法而已。只有有何妙用下面會繼續(xù)講解)。且?編譯后同樣帶上了靜態(tài)類名。
擴(kuò)展方法可以做些什么
- 把已有的靜態(tài)方法轉(zhuǎn)成擴(kuò)展方法:如:
調(diào)用:?
string str = null; var isNull = str.IsNullOrEmpty();?感覺相比期靜態(tài)方法調(diào)用要優(yōu)雅,更接近我們的自然語言。
- ?可以編寫很多的幫助類,如(以string為例):
上面所有的都只是擴(kuò)展方法的附加用處,擴(kuò)展方法真正的威力是為Linq服務(wù)的(主要體現(xiàn)于IEnumerable和IQueryable),實(shí)現(xiàn)鏈?zhǔn)骄幊獭O旅嫖覀冏约簛韺?shí)現(xiàn)所謂的鏈?zhǔn)骄幊?#xff1a;
初始化?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;}}調(diào)用:(這里僅僅為了演示,所以不要討論實(shí)現(xiàn)是否合理、算法是否高效。)
var newPersons = persons.MyWhere(t => t.DeathTime == null).MyOrderByDescending(t => t.BirthTime); foreach (var item in newPersons) {Console.WriteLine(item.BirthTime); }就是如此簡單的實(shí)現(xiàn)了所謂的函數(shù)式編程。結(jié)果圖如下:
這樣一句代碼搞定所有邏輯,像自然語言般的流暢。其實(shí).net為IEnumerable實(shí)現(xiàn)了這樣的擴(kuò)展,如:
執(zhí)行結(jié)構(gòu)和上面一模一樣。
?
其實(shí)擴(kuò)展方法也可以當(dāng)成靜態(tài)方法來使用:
var p1 = ExtensionClass.MyWhere(persons, t => t.DeathTime == null);var p2 = ExtensionClass.MyOrderByDescending(p1, t => t.BirthTime);var p3 = ExtensionClass.MyOrderBy(p2, t => t.BirthTime);(不信?繼續(xù)看,有圖有真相)
?
C#代碼:
?
反編譯C#的代碼:(你是不是看到了,編譯后直接就是使用的擴(kuò)展方法的形式。)
反編譯的IL代碼:
雖然編譯后的代碼是一樣的,但是做為程序員的我們更喜歡哪種方式呢?
?
總結(jié):
我們在對擴(kuò)展方法的怎么使用疑惑或者忘記了規(guī)則的時(shí)候,我們不用去查找資料說:
我們只需記住,當(dāng)你不知道怎么編寫或使用擴(kuò)展方法時(shí),你先把它當(dāng)成靜態(tài)方法編寫或使用。如果可行,一般都可以轉(zhuǎn)成擴(kuò)展方法的形式。
?
全部代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using System.Data.Entity.Utilities; using System.Diagnostics.CodeAnalysis; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using System.IO;namespace test {class Program{static void Main(string[] args){/* * 1.工具類* 2.鏈?zhǔn)骄幊?/span>*/string str = null;var isNull = str.IsNullOrEmpty();var p = new Person() { BirthTime = DateTime.Parse("1990-07-19") };var age = p.GetAge();age = ExtensionClass.GetAge2(p);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")}};var newPersons = persons.MyWhere(t => t.DeathTime == null).MyOrderByDescending(t => t.BirthTime);var p1 = ExtensionClass.MyWhere(persons, t => t.DeathTime == null);var p2 = ExtensionClass.MyOrderByDescending(p1, t => t.BirthTime);var p3 = ExtensionClass.MyOrderBy(p2, t => t.BirthTime);foreach (var item in newPersons){Console.WriteLine(item.BirthTime);}Console.ReadKey();}}public sealed class Person{/// <summary>/// 出生日期/// </summary>public DateTime BirthTime { get; set; }/// <summary>/// 死亡日期/// </summary>public DateTime? DeathTime { get; set; }}//public class MyPerson : Person//{// public int GetAge()// {// if (DeathTime.HasValue)// return (DeathTime.Value - BirthTime).Days / 365;// else// return (DateTime.Now - BirthTime).Days / 365;// }//}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;}public static int GetAge2(Person person){if (person.DeathTime.HasValue)return (person.DeathTime.Value - person.BirthTime).Days / 365;elsereturn (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;elsereturn (DateTime.Now - person.BirthTime).Days / 365;}public static bool IsNullOrEmpty(this string str){return string.IsNullOrEmpty(str);}} } View Code?
本文以同步至《C#基礎(chǔ)知識鞏固系列》
轉(zhuǎn)載于:https://www.cnblogs.com/RYouHoo-923/p/8267517.html
總結(jié)
以上是生活随笔為你收集整理的【转】五、谈扩展方法的理解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python __builtins__
- 下一篇: MyBatis无限输出日志