Visual Basic和C#中的LINQ聚合

来源:论坛
  Aggregate是一个可以从一个数据集合中获取标量值的函数,比如T-SQL中的Min()、Max()和Sum()等。现在VB和C#也都对这种聚合的功能给于了支持,但是是以一种非常不同的方式。

  VB和C#都是以扩展方法的形式支持聚合的。在一个IEnumberable对象中,一个简单的调用是通过点符号完成的,比如:

  var totalVirtualMemory = (from p in Process.GetProcesses()
  select p.VirtualMemorySize64).Sum();
  Dim totalVirtualMemory = _
  (From p In Process.GetProcesses _
  Select p.VirtualMemorySize64).Sum
  从这儿可以看到,VB和C#的版本几乎是一样的。但VB还为聚合专门提供了一个LINQ语法:

  Dim totalVirtualMemory = Aggregate p In Process.GetProcesses _ Into p.VirtualMemorySize64

  如果这是二者之间唯一区别的话,那么也就没有什么好谈的了。但是,有趣的事情发生在当你想同时操作不止一个“列”的时候。简便起见,我们假设要操作正在使用的全部虚拟内存和全部工作集(物理内存)。

  使用匿名类,我们可以轻松地创建一个带有它们两个值的变量。
  var totals = new {

  totalVirtualMemory = (from p in Process.GetProcesses() select p.VirtualMemorySize64).Sum(),

  totalWorkingSet = (from p in Process.GetProcesses() select p.WorkingSet64).Sum() };   

  这儿的问题是GetProcesses()被调用了两次。也就是说操作系统必须查询两次,在结果集合中执行两次循环。一个更快的方法也许是对GetProcesses()的调用进行缓存。

  var processes = (from p in Process.GetProcesses() select new { p.VirtualMemorySize64, p.WorkingSet64 } ).ToList();

  var totals2 = new { totalVirtualMemory = (from p in processes select p.VirtualMemorySize64).Sum(),

  totalWorkingSet = (from p in processes select p.WorkingSet64).Sum()

  };   

  虽然好了一些,但仍然需要两次循环。如何只执行一次呢?这时我们需要一个定制的聚合器,和一个保存这些结果的命名类(Named Class)。

  public static ProcessTotals Sum(this IEnumerable source) {
  var totals = new ProcessTotals();
  foreach (var p in source){
  totals.VirtualMemorySize64 += p.VirtualMemorySize64;
  totals.WorkingSet64 += p.WorkingSet64;
  }

  return totals;

  }

  public class ProcessTotals {

  public long VirtualMemorySize64 { get; set; }
  public long WorkingSet64 { get; set; }

  }

  var totals3 = (from p in Process.GetProcesses() select p).Sum();
  开发者在Visual Basic中也可以这样做,但需要像下面这样做:
  Dim totals3 = Aggregate p In Process.GetProcesses _
  Into virtualMemory = Sum(p.VirtualMemorySize64), _
  workingSet = Sum(p.WorkingSet64)

  就像在上一个C#例子中,我们是用一个含有两个Field的变量解决问题的。但这和C#的例子不一样,你不会因为是选择创建自己的聚合函数及类还是在遍历集合中浪费两次循环,而左右为难。

  公平起见,C#确实还有那么几招。不像VB那样只支持单行的匿名函数,只要需要,C#可以让它们很复杂,这就使得它可以在需要的时候创建匿名的聚合函数。

  var processes = (from p in Process.GetProcesses() select new { p.VirtualMemorySize64, p.WorkingSet64 });

  var totals4 = processes.Aggregate(new ProcessTotals(), (sum, p) => { sum.WorkingSet64 += p.WorkingSet64;

  sum.VirtualMemorySize64 += p.VirtualMemorySize64; return sum;

  });

  注意在这儿,ProcessTotals类依然需要用到。匿名类不能被用在这儿,因为C#匿名类是不可变的。虽然Visual Basic的匿名类可以改变,但是在这儿也没用,因为VB不能创建多行的匿名函数。

  但是Visual Basic和C#都较从前有了强有力的改进,双方也各有长处,让对方在不足之处加油赶上。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值