【IEnumerable】扩展方法的使用 C#
直接進入主題吧...
??? ?? IEnumerable :?公開枚舉數,該枚舉數支持在非泛型集合上進行簡單迭代。 好吧,迭代,我就理解成循環,這些名詞真晦澀,沒意思
??? ?? 今天看的是 Using Extension Methods ,使用"擴展方法"。俺都開始看英文文檔了,得瑟中...
??? ?? 所謂擴展方法,是對類型的擴展。如對string擴展一個GotoHell(); 方法,可以這樣用? “damn”.GotoHell();
??? ?? 如何實現呢,咱創建一個新的類,叫做StringExtend,有這樣一個方法,
??? ? ? public static string GotoHell(this string str)
?? ? ? ?{
??? ? ??? ?? return str+"GotoHell";
?? ? ? ? }
??? ? ? 然后在另一處調用(同一個命名空間哦),"Damn ".GotoHell();? 輸出的值為:“Damn GotoHell” (由此看出,我心情卻是不好啊)
??? ??? 這是一般類型的擴展方法,似乎與主題那不搭邊呢,好吧,我跑題了。
??? ? ? IEnumerable 我也不管他是什么東西,反正就理解像是一個列表的東西。而實際上List是繼承的IEnumerable。
??? ? ? 為了使程序更形象,于是俺創建一個實體類:
?? ? ?? public class Product
???? ? {
?????? ?? public string Name { get; set; }
????? ? ? public string Category { get; set; }
????? ? ? public decimal Price { get; set; }
? ? ? }
??? ? 這兒又得跳躍一下,Using Automatically Implemented Properties。也就是public string Name{get;set;} 對應的英文定義了。
??? ? 翻譯為:自動實現的屬性。為啥叫自動實現的屬性,都實現了哪些呢? 如果不這樣寫,那就需要這樣:
??? ? get{ return name; } // 這里還需要創建一個name變量
??? ? set{ name=value;}
????? 確實比較繁瑣,耦合性也稍微高一些,同時效率也稍微低一些。
??? ? 【Tag1】現在我們來點數據:
??? ? IEnumerable<Product> products = new List<Product> {
??????????? new Product{Name="one",Category="rose",Price=56},
??????????? new Product{Name="two",Category="jack",Price=55},
??????????? new Product{Name="three",Category="jack",Price=54}
??????????? };
??? ?? 上面說過了,IEnum... 就像是個列表的東西,List 實現了它,這樣賦值不足為過吧。
??? ?? 那現在我要篩選出 Category 為jack 的數據,怎么辦呢。咱新建一個List temp ? 對吧,怕啥啊,不就浪費點內存嗎,咱有的是。
??? ?? 好吧,我以前就是這么想的,而如今,我覺得那樣做,太TM操蛋了。
??? ? ----------------------
?? ??? 我新建一個類:MyextendClass
??? ?? public static IEnumerable<Product> FilterByCategory(this IEnumerable<Product> productEnum,string categoryParam)
?? ? ? {
??? ? ? ? ? ? foreach(Product pro in productEnum)?? // 這里我習慣性寫成 foreach(var item in productEnum)
????????????? {
????????????????? if(pro.Category==categoryParam)
????????????? ? ? {
??????????????? ? ? ? yield return pro;? // yield 是什么鳥玩意兒啊? 我只知道他用在迭代器里面,告訴他這里結束了,下次你來迭代的時候往下一個迭代走。同時呢,他發現一個東西就立即返回過去,不要等待集合裝入完畢,據說效 率杠杠滴哦。這是我的理解,有大蝦的話,請留言更正。
?????????????????? }
?????????????? }
?? ? ? }
????? 然后,就調用了:products.FilterByCategory("jack"); 好了,這樣就獲取了 category 為 jack 的列表,你想怎么處理輸出都是你的事情了。
???? 再想想,如果我要計算jack分類的Price的總和呢?如果N多地方出現這種情況,難道我們都要重新寫方法嗎?話說,就算寫好了,以后也不好維護呢。好吧,咱再擴展一個唄:
public static decimal TotalPrice(this IEnumerable<Product> productEnum)
{
??? decimal total=0;
??? foreach(var item in productEnum)
??? {
?? ??? ? total+=item.Price;
?? ? }
???? return total;
}
Wonderful,這樣我們就這樣調用:products.FilterByCategory("jack").TotalPrice(); 是不是很方便,以后要修改這部分代碼頁相當方便。
只要一處擴展這個方法,到處都可以用。維護固然就很方便了。
有這么一種情況,我想按某種方式過濾出數據,可是我現在還不知道要怎么過濾。我需要把這一層寫好先。然后有時間我再去獨立的思考那一方面的邏輯。委托? 我給你參數和我需要的返回值類型,之后你要干嘛干嘛去,我不管了(這不就是漢語中委托的意思么,呵呵)。
這里有這樣一個委托: Func<in T,out TResult> 給個T的參數,返回TResult 類型的值(話說對 泛型 了解的還不夠深刻,不管亂解釋,改天我再去瞅瞅)。
好了,寫擴展方法咯:
public static IEnumerable<Product> Filter(this IEnumerable<product> productEnum,Func<Product,bool> selectorParam)
{
??? foreach(var item in productEnum){
??? ? ?? if(selectorParam(item)){
????????????? yield return item;
?? ? ? ? ?}
?? ?}
}
那委托都干了點啥呢?我們調用前給他賦予它的使命:
Func<Product,bool> categoryfilter=delegate(Product pro){? reutrn pro.Category=="rose";? };
products.Filter(categoryfilter); //終于得到rose了。
有沒有一種方式,再簡化下這種委托呢?有的,Lamada (這個我也不是很熟,改天一并看了吧):
Func<Product,bool> categoryfilter=pro=>pro.Category=="rose";
(好吧,關于擴展方法我就看了這么些,輸出結果為 兩個 “jack” ,一個 “rose” . 這男女比例真的失衡了,這咋分啊。? ??)
最后提一句,在【Tag1】的時候,IEnumerable 也可以寫成 IList 或 其他類似的 繼承了 IEnumerable 的類型或接口。
通過使用 IEnumerable 可以定制適合自己開發過程中的基本邏輯,就像PS中錄制動作一般,相當使用。
又如一個例子:假設在B2C站中,商品詳情頁有商品評論,商品評論已經緩存了下來(我想這是必要的)。
在顯示評價時,有這樣的需求,如果是置頂的則排在最前面,其次是精華評論,再者就是其他。
方案a.我們可以使用正常的邏輯去處理,整出幾十行代碼。如果在其他使用類似的邏輯,只是過濾條件變了,我們又得重新寫這部分的邏輯。
方案b.如果我們新建一個擴展類,將這部分邏輯添加到擴展中。只需業務邏輯中添加幾行代碼便可實現需求。不僅從代碼的美觀上還是在系統的維護上都有很大的好處。
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleTest
{
??? class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? IList<RefModel> list = Init();
??????????? IList<RefModel> list2 = list.Filter_Attr(r => r.IsTop == true && r.Sex == "boy").ToList();
??????????? Console.WriteLine("-------------------過濾-----------------------");
??????????? foreach (var item in list2)
??????????? {
??????????????? Console.WriteLine(item.Name + "? " + (item.IsTop ? "[T]? " : "") + (item.IsElite ? "[E]? " : "") + "[" + item.Sex + "]");
??????????? }
??????????? Console.WriteLine("-------------------重組:原順序---------------------------");
??????????? foreach (var item in list)
??????????? {
??????????????? Console.WriteLine(item.Name + "? " + (item.IsTop ? "[T]? " : "") + (item.IsElite ? "[E]? " : ""));
??????????? }
??????????? Console.WriteLine("-------------------重組:規則排序后----------------------------");
??????????? list = list.Filter_Order().ToList();
??????????? foreach (var item in list)
??????????? {
??????????????? Console.WriteLine(item.Name + "? " + (item.IsTop ? "[T]? " : "") + (item.IsElite ? "[E]? " : ""));
??????????? }
??????????? Console.ReadLine();
??????? }
??????? private static IList<RefModel> Init()
??????? {
??????????? IList<RefModel> list = new List<RefModel>(){
??????????????? new RefModel { Name = "charles", Sex = "boy", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles1", Sex = "girl", IsTop = true, IsElite = false },
??????????????? new RefModel { Name = "charles2", Sex = "girl", IsTop = false, IsElite = true },
??????????????? new RefModel { Name = "charles3", Sex = "boy", IsTop = false, IsElite = true },
??????????????? new RefModel { Name = "charles4", Sex = "girl", IsTop = true, IsElite = false },
??????????????? new RefModel { Name = "charles5", Sex = "girl", IsTop = false, IsElite = true },
??????????????? new RefModel { Name = "charles6", Sex = "boy", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles7", Sex = "girl", IsTop = true, IsElite = false },
??????????????? new RefModel { Name = "charles8", Sex = "boy", IsTop = false, IsElite = false },
??????????????? new RefModel { Name = "charles9", Sex = "girl", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles10", Sex = "boy", IsTop = false, IsElite = false },
??????????????? new RefModel { Name = "charles11", Sex = "boy", IsTop = false, IsElite = false },
??????????????? new RefModel { Name = "charles12", Sex = "girl", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles13", Sex = "boy", IsTop = false, IsElite = false },
??????????????? new RefModel { Name = "charles14", Sex = "boy", IsTop = false, IsElite = true },
??????????????? new RefModel { Name = "charles15", Sex = "girl", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles16", Sex = "girl", IsTop = false, IsElite = false },
??????????????? new RefModel { Name = "charles17", Sex = "boy", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles18", Sex = "boy", IsTop = false, IsElite = true },
??????????????? new RefModel { Name = "charles19", Sex = "girl", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles20", Sex = "boy", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles21", Sex = "boy", IsTop = false, IsElite = false },
??????????????? new RefModel { Name = "charles22", Sex = "girl", IsTop = true, IsElite = true },
??????????????? new RefModel { Name = "charles23", Sex = "boy", IsTop = true, IsElite = false },
??????????????? new RefModel { Name = "charles24", Sex = "boy", IsTop = true, IsElite = true }};
??????????? return list;
??????? }
??? }
??? public class RefModel
??? {
??????? public string Name { get; set; }
??????? public string Sex { get; set; }
??????? public bool IsTop { get; set; }
??????? public bool IsElite { get; set; }
??? }
}
using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace ConsoleTest {public static class Filter{public static IEnumerable<RefModel> Filter_Attr(this IEnumerable<RefModel> list, Func<RefModel, bool> selectorParam){foreach (var item in list){if (selectorParam(item)){yield return item;}}}public static IEnumerable<RefModel> Filter_Order(this IEnumerable<RefModel> list){IList<RefModel> topList = new List<RefModel>();IList<RefModel> eliteList = new List<RefModel>();IList<RefModel> elseList = new List<RefModel>();foreach (var item in list){if (item.IsTop){topList.Add(item);//yield return item;//Tag FX }else if (item.IsElite){eliteList.Add(item);}else{elseList.Add(item);}}///Tag X Start foreach (var item in topList){yield return item;}///Tag X End foreach (var item in eliteList){yield return item;}foreach (var item in elseList){yield return item;}}} }
運行結果:(部分)
最后如果理解 yield 的用法,那么可以將上述代碼中 Tag X 行取消注釋,并將 Tag X Start 內的代碼注釋掉,將得到相同的結果。這樣講減少一層循環。雖然效率提高的微乎其微,但卻如我博客Header所述:不積跬步無以至千里。
???????
如對你有幫助,輕輕地東東手指,Recomend Or Comment 。 你的支持是我的不斷前行的動力。???????????????????????????? 歡迎轉載。
轉載于:https://www.cnblogs.com/shenchaoming/archive/2013/03/25/IEnumerable.html
總結
以上是生活随笔為你收集整理的【IEnumerable】扩展方法的使用 C#的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单高效,分享几款我在使用的效率神器
- 下一篇: Windows下安装pip