Aggregate是一個可以從一個數據集合中獲取標量值的函數比如TSQL中的Min()Max()和Sum()等現在VB和C#也都對這種聚合的功能給於了支持但是是以一種非常不同的方式
VB和C#都是以擴展方法的形式支持聚合的在一個IEnumberable對象中一個簡單的調用是通過點符號完成的比如
var totalVirtualMemory = (from p in ProcessGetProcesses()
select pVirtualMemorySize)Sum();
Dim totalVirtualMemory = _
(From p In ProcessGetProcesses _
Select pVirtualMemorySize)Sum
從這兒可以看到VB和C#的版本幾乎是一樣的但VB還為聚合專門提供了一個LINQ語法
Dim totalVirtualMemory = Aggregate p In ProcessGetProcesses _ Into pVirtualMemorySize
如果這是二者之間唯一區別的話那麼也就沒有什麼好談的了但是有趣的事情發生在當你想同時操作不止一個列的時候簡便起見我們假設要操作正在使用的全部虛擬內存和全部工作集(物理內存)
使用匿名類我們可以輕松地創建一個帶有它們兩個值的變量
var totals = new {
totalVirtualMemory = (from p in ProcessGetProcesses() select pVirtualMemorySize)Sum()
totalWorkingSet = (from p in ProcessGetProcesses() select pWorkingSet)Sum() };
這兒的問題是GetProcesses()被調用了兩次也就是說操作系統必須查詢兩次在結果集合中執行兩次循環一個更快的方法也許是對GetProcesses()的調用進行緩存
var processes = (from p in ProcessGetProcesses() select new { pVirtualMemorySize pWorkingSet } )ToList();
var totals = new { totalVirtualMemory = (from p in processes select pVirtualMemorySize)Sum()
totalWorkingSet = (from p in processes select pWorkingSet)Sum()
};
雖然好了一些但仍然需要兩次循環如何只執行一次呢?這時我們需要一個定制的聚合器和一個保存這些結果的命名類(Named Class)
public static ProcessTotals Sum(this IEnumerable source) {
var totals = new ProcessTotals();
foreach (var p in source){
totalsVirtualMemorySize += pVirtualMemorySize;
totalsWorkingSet += pWorkingSet;
}
return totals;
}
public class ProcessTotals {
public long VirtualMemorySize { get; set; }
public long WorkingSet { get; set; }
}
var totals = (from p in ProcessGetProcesses() select p)Sum();
開發者在Visual Basic中也可以這樣做但需要像下面這樣做
Dim totals = Aggregate p In ProcessGetProcesses _
Into virtualMemory = Sum(pVirtualMemorySize) _
workingSet = Sum(pWorkingSet)
就像在上一個C#例子中我們是用一個含有兩個Field的變量解決問題的但這和C#的例子不一樣你不會因為是選擇創建自己的聚合函數及類還是在遍歷集合中浪費兩次循環而左右為難
公平起見C#確實還有那麼幾招不像VB那樣只支持單行的匿名函數只要需要C#可以讓它們很復雜這就使得它可以在需要的時候創建匿名的聚合函數
var processes = (from p in ProcessGetProcesses() select new { pVirtualMemorySize pWorkingSet });
var totals = processesAggregate(new ProcessTotals() (sum p) => { sumWorkingSet += pWorkingSet;
sumVirtualMemorySize += pVirtualMemorySize; return sum;
});
注意在這兒ProcessTotals類依然需要用到匿名類不能被用在這兒因為C#匿名類是不可變的雖然Visual Basic的匿名類可以改變但是在這兒也沒用因為VB不能創建多行的匿名函數
但是Visual Basic和C#都較從前有了強有力的改進雙方也各有長處讓對方在不足之處加油趕上
From:http://tw.wingwit.com/Article/program/net/201311/12062.html