在平時開發中經常會看到有些朋友或者同事在寫代碼時會充斥著各種for,foreach,這種程式代碼太多的話閱讀性特別差,而且還顯得特別累贅,其實在FCL中有很多幫助我們提高閱讀感的方法,而現實中很多人不會用或者說不知道,這篇我就跟大家聊一聊,
一:SelectMany
這個方法絕對是提高開發速度的一大利器,有太多的業務場景需要使用這個函式,舉一個我實際應用場景,商家按照年份和客戶型別預先設定一些標簽,然后讓系統跑一下它的各自標簽到底有多少人?
1. 定義Model
為了方便演示,這里做了一下簡化代碼,只有一個字典,key表示年份,value:就是該年份的多組標簽,
public class EstimateModel
{
public int ShopID { get; set; }
//key: 年份
public Dictionary<string, List<TagCrowdFilterModel>> YearCrowdFilterDict { get; set; }
}
public class TagCrowdFilterModel
{
/// <summary>
/// 篩選條件
/// </summary>
public string CrowdFiter { get; set; }
/// <summary>
/// 獲取人數
/// </summary>
public int TotalCustomerCount { get; set; }
}
為了更加清晰,我決定再填充一下資料
public static void Main(string[] args)
{
var estimateModel = new EstimateModel()
{
ShopID = 1,
YearCrowdFilterDict = new Dictionary<string, List<TagCrowdFilterModel>>()
{
{
"17年",new List<TagCrowdFilterModel>()
{
new TagCrowdFilterModel(){ CrowdFiter="between 10 and 20" },
new TagCrowdFilterModel(){ CrowdFiter=" a<10 || a>30" },
}
},
{
"18年",new List<TagCrowdFilterModel>()
{
new TagCrowdFilterModel(){ CrowdFiter="between 100 and 200" },
new TagCrowdFilterModel(){ CrowdFiter=" a<100 || a>300" },
}
},
{
"19年",new List<TagCrowdFilterModel>()
{
new TagCrowdFilterModel(){ CrowdFiter="between 1000 and 2000" },
new TagCrowdFilterModel(){ CrowdFiter=" a<1000 || a>3000" },
}
}
}
};
}
public static int GetCustomerID(string crowdfilter)
{
return BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
}
2. 實作需求
需求也很簡單,就是依次獲取 TagCrowdFilterModel 中的 CrowdFiter 欄位再呼叫GetCustomerID方法把人數賦值給TotalCustomerCount即可,這么簡單的需求,如果讓你來搞定,你該怎么實作這個邏輯? 沒錯,很多人可能就是兩個foreach搞定,
foreach (var year in estimateModel.YearCrowdFilterDict.Keys)
{
var yearCrowdFitlerList = estimateModel.YearCrowdFilterDict[year];
foreach (var crowdFitler in yearCrowdFitlerList)
{
crowdFitler.TotalCustomerCount = GetCustomerID(crowdFitler.CrowdFiter);
}
}
看似代碼也很清爽,但現實哪有這么好的事情,真實情況是年份上可能還要套上一個客戶型別,客戶型別之上再套一個商品,商品之上再套一個商家,這樣很深的層級你就需要多達3個foreach,4個foreach甚至5個foreach才能搞定,再放張圖給大家看看,是不是看著頭大...??

3. 優化辦法
如果你會selectMany,那只需要一個鏈式寫法就可以搞定,是不是簡單粗暴,雖然性能比不上命令式寫法,但可讀性和觀賞性真的上了幾個檔次,
estimateModel.YearCrowdFilterDict.SelectMany(m => m.Value).ToList().ForEach(m =>
m.TotalCustomerCount = GetCustomerID(m.CrowdFiter)
);
二:原理探究
1. msdn解釋
將序列的每個元素投影到 IEnumerable
https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.enumerable.selectmany?view=netframework-4.8
有了上面的案例解釋,再看msdn的這句話,我想你應該徹徹底底的明白了selectMany怎么使用,
2. 翻查原始碼
宏觀上明白了,接下來用ILSpy去查下微觀代碼,到底這玩意是怎么實作的,
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (selector == null)
{
throw Error.ArgumentNull("selector");
}
return SelectManyIterator(source, selector);
}
private static IEnumerable<TResult> SelectManyIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
foreach (TSource item in source)
{
foreach (TResult item2 in selector(item))
{
yield return item2;
}
}
}
大家仔細體會下這兩個foreach,尤其是第二個foreach,其中的selector(item)不就是年份下的標簽集合嗎?再遍歷這個集合把每一個item回傳出去,回傳值是IEnumerable
好了,本篇就說到這里,希望對你有幫助,
如您有更多問題與我互動,掃描下方進來吧~


轉載請註明出處,本文鏈接:https://www.uj5u.com/net/52830.html
標籤:C#
