9 月 13 日,2025 Inclusion・外滩大会「开源嘉年华」正在限量报名中! 了解详情
写点什么

VB 和 C#中的 LINQ 聚合

  • 2007-09-18
  • 本文字数:1954 字

    阅读完需:约 6 分钟

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

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

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

<pre dir="ltr"><p dir="ltr">Dim totalVirtualMemory = Aggregate p In Process.GetProcesses _ </p><p dir="ltr"> Into p.VirtualMemorySize64</p>如果这是二者之间唯一区别的话,那么也就没有什么好谈的了。但是,有趣的事情发生在当你想同时操作不止一个“列”的时候。简便起见,我们假设要操作正在使用的全部虚拟内存和全部工作集(物理内存)。

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

<pre dir="ltr"><p dir="ltr">var totals = new <br></br>{ <br></br> totalVirtualMemory = (from p in Process.GetProcesses() </p><p dir="ltr"> select p.VirtualMemorySize64).Sum(), <br></br> totalWorkingSet = (from p in Process.GetProcesses() </p><p dir="ltr"> select p.WorkingSet64).Sum() <br></br>};</p>这儿的问题是 GetProcesses() 被调用了两次。也就是说操作系统必须查询两次,在结果集合中执行两次循环。一个更快的方法也许是对 GetProcesses() 的调用进行缓存。

<pre dir="ltr"><p dir="ltr">var processes = (from p in Process.GetProcesses() <br></br> select new { p.VirtualMemorySize64, p.WorkingSet64 }</p><p dir="ltr"> ).ToList();</p><p dir="ltr"><br></br>var totals2 = new <br></br>{ <br></br> totalVirtualMemory = (from p in processes <br></br> select p.VirtualMemorySize64).Sum(), <br></br> totalWorkingSet = (from p in processes <br></br> select p.WorkingSet64).Sum() <br></br>};</p>虽然好了一些,但仍然需要两次循环。如何只执行一次呢?这时我们需要一个定制的聚合器,和一个保存这些结果的命名类(Named Class)。

<pre dir="ltr"><p dir="ltr">public static ProcessTotals Sum(this IEnumerable source) <br></br>{ <br></br> var totals = new ProcessTotals(); <br></br> foreach (var p in source){ <br></br> totals.VirtualMemorySize64 += p.VirtualMemorySize64; <br></br> totals.WorkingSet64 += p.WorkingSet64; <br></br> } <br></br> return totals; <br></br>} </p><p>public class ProcessTotals </p><br></br>{ <br></br> public long VirtualMemorySize64 { get; set; } <br></br> public long WorkingSet64 { get; set; } <br></br>} <p>var totals3 = (from p in Process.GetProcesses() select p).Sum();</p>开发者在 Visual Basic 中也可以这样做,但需要像下面这样做:

<pre dir="ltr"><p dir="ltr">Dim totals3 = Aggregate p In Process.GetProcesses _ <br></br> Into virtualMemory = Sum(p.VirtualMemorySize64), _<br></br> workingSet = Sum(p.WorkingSet64)</p>就像在上一个 C#例子中,我们是用一个含有两个 Field 的变量解决问题的。但这和 C#的例子不一样,你不会因为是选择创建自己的聚合函数及类还是在遍历集合中浪费两次循环,而左右为难。

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

<pre dir="ltr"><p dir="ltr">var processes = <br></br> (from p in Process.GetProcesses() <br></br> select new { p.VirtualMemorySize64, p.WorkingSet64 }); <br></br>var totals4 = processes.Aggregate(new ProcessTotals(), (sum, p) => <br></br> { <br></br> sum.WorkingSet64 += p.WorkingSet64; <br></br> sum.VirtualMemorySize64 += p.VirtualMemorySize64; <br></br> return sum;</p><p dir="ltr"> });</p>注意在这儿,ProcessTotals 类依然需要用到。匿名类不能被用在这儿,因为 C#匿名类是不可变的。虽然 Visual Basic 的匿名类可以改变,但是在这儿也没用,因为 VB 不能创建多行的匿名函数。

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

查看英文原文: LINQ Aggregates in VB and C#

2007-09-18 04:261513

评论

发布
暂无评论
发现更多内容

Android面试主题整理合集(一),android开发前景

android 程序员 移动开发

Android面试官,面试时总喜欢挖基础坑,整理了26道面试题牢固你基础

android 程序员 移动开发

Android面试题之Broadcast Receiver篇,你们觉得作为一名程序员最大的悲哀是什么

android 程序员 移动开发

Android面试:计算机网络面试知识点系统总结,拔剑金九银十(1)

android 程序员 移动开发

android进阶篇04、MVC、MVP,腾讯大牛教你自己写Android框架

android 程序员 移动开发

android进阶篇11、crash监控与anr分析简述,vue双向绑定原理

android 程序员 移动开发

Android面经分享:从15K到32K,从小厂到大厂,android系统开发面试

android 程序员 移动开发

Android面试题之动画+事件处理篇,腾讯、美团Android面试经验分享

android 程序员 移动开发

Android面试复盘:认真刷题,掌握原理很重要,【深夜思考】

android 程序员 移动开发

Android面试抱佛脚:进程间通讯学习,从Binder使用看起

android 程序员 移动开发

Android面试:一个进程有多少个-Context-对象?看似初级的问题

android 程序员 移动开发

android进阶篇09、电量与网络优化简述,android内存优化方案

android 程序员 移动开发

Android静态代码扫描效率优化与实践,2021大厂Android面试经历

android 程序员 移动开发

Android面试必备知识点:Android中Handler八大问题汇总

android 程序员 移动开发

Android面试题之性能优化篇(1),移动开发工程师的岗位职责

android 程序员 移动开发

RPC就好像是谈一场异地恋

博文视点Broadview

一个程序员眼中的项目经理

神策技术社区

OKR 项目经理

Android面试题之性能优化篇,当上项目经理才知道

android 程序员 移动开发

Android进阶:最简单的方式实现自定义阴影效果,7年老Android一次坑爹的面试经历

android 程序员 移动开发

Android面试指南(三),kotlin匿名内部类写法

android 程序员 移动开发

Android进阶:三、这一次,从入门到精通系列Android高级工程师路线介绍

android 程序员 移动开发

Android面试题之性能优化篇(2),安卓高级开发面试题

android 程序员 移动开发

Android进阶:知识遗忘真的是程序员的通病吗?其实是这些新知识的学习方法你还没get到

android 程序员 移动开发

Android面经分享:我是如何拿到腾讯头条美团小米的offer从小厂跳到大厂的?

android 程序员 移动开发

Android面试反思:开发5年crud背景,惨遭字节阿里双挂,网站开发前后端分离

android 程序员 移动开发

Apache APISIX 社区周报 | 2021 10.15-10.31

API7.ai 技术团队

API网关 社区周报 Apache APISIX

Android面试必问之Binder进程间通信机制,大厂喜欢从哪些角度考你呢?看完这篇你就懂啦

android 程序员 移动开发

Android达到什么水平才能顺利拿到 20k 无压力?,Android基础开发与实践

android 程序员 移动开发

Android进阶——Android跨进程通讯机制之Binder,okhttp读取信息kotlin

android 程序员 移动开发

Android转战Web前端,靠着这份面试题和答案,一举拿下京东offer

android 程序员 移动开发

Android面试官:看你简历上写熟悉-AIDL,说一说-oneway-吧

android 程序员 移动开发

VB和C#中的LINQ聚合_.NET_Jonathan Allen_InfoQ精选文章