[读书笔记][第十一章] C# in depth

本文是C# in depth第十一章读书笔记,重点介绍了查询表达式(如from select、where、orderby、join、let、group by等)和LINQ to Objects的使用。探讨了查询表达式的延迟执行、范围变量、筛选排序、连接、分组等概念,并通过示例展示了如何转换为C#代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ch 11 查询表达式和 LINQ to Objects

intro

  • Language Integrated Query (LINQ), C# 3的新特性。
  • 标准查询操作符 -> 构成查询表达式 -> 转译为普通c#3 代码 -> 编译(推断、重载、Lambda表达式)
  • 序列:一次只能取当前的那个元素。IEnumerable
  • 延迟执行和流处理:查询表达式被创建时,不会访问数据,而是在内存中生成了这个查询的表现形式。过滤判断通过委托实例来表示,只有在访问结果的第一个元素的时候,才开始执行。每次只处理一个元素。
  • 范围变量 (range variable)
  • 声明式而非命令式,函数式编程思想

思考

  • 何时使用查询表达式、何时使用点标记?

选择元素: from select

from 范围变量 in 数据源 where 过滤 select 投影

//11-2
from user in SampleData.AllUsers 
            select user;

转译=> SampleData.AllUsers.Select(user => user);

显式类型的范围变量:Cast, OfType

范围变量都可以是隐式类型。Cast,OfType将飞类型化序列转化为强类型。 遇到不匹配类型,Cast报错,OfType跳过。

//11-5
ArrayList list = new ArrayList { "First", "Second", "Third"};
IEnumerable<string> strings = list.Cast<string>();

list = new ArrayList { 1, "not an int", 2, 3};
IEnumerable<int> ints = list.OfType<int>();

筛选排序:where, orderby

where

//11-8
User tim = SampleData.Users.TesterTim;
var query = from defect in Sample
    where defect.Status != Status.Closed
    where defect.AssignedTo = tim
    select defect.Summary;
  • Q. 多个where,何时合并?
  • A. 逻辑上关联的条件合并在一起,逻辑上不关联的保持独立。这里两个where可以合并。

退化的查询表达式:select item

.Select(defect => defect)

查询表达式的结果和源数据永远不会是同一个对象,对返回数据集的改变也不会影响到“主”数据。

  • orderby descending =>转译=> OrderByDescending() 或者 ThenByDescending()
  • orderby =>转译=> OrderBy() 或者 ThenBy(),默认ascending
  • ThenBy() 对之前的一个或多个排序规则起辅助作用,是定义为 IOrderedEnumerable<T>的扩展方法

透明标识符: let

<CSharp 4 Specification> 7.16.2.4 From, let, where, join and orderby clauses

A query expression with a let clause from x in e let y = f is translated into from * in ( e ) . Select ( x => new { x , y = f } )

连接:join

内连接:inner join

inner = left, outer = right 内连接从某个对象导航到另一个对象。对右边序列进行缓冲,对左边序列进行流处理。 在SQL中,内连接通常是把某个表的外键和另一个表的主键进行连接。

//11-12
from defect in SampleData.AllDefects
    join subscription in SampleData.AllSubscriptions
        on defect.Project equals subcription.Project
    select new {defect.Summary, subscription.EmailAdress};

send defect to subcripter's emailbox

=>转译=>

leftSequence.Join(rightSequence,
    leftKeySelector,
    rightKeySelector,
    resultSelector)

where

  • in left sequence
from defect in SampleData.AllDefects
    where defect.Status == Status.Closed
    join subscription in SampleData.AllSubscriptions
        on defect.Project equals subcription.Project
    select new {defect.Summary, subscription.EmailAdress};
  • in right sequence
from subscription in SampleData.AllSubscriptions
    join defect in (from defect in SampleData.AllDefects
            where defect.Status == Status.Closed
            select defect)
        on defect.Project equals subcription.Project
    select new {defect.Summary, subscription.EmailAdress};

分组连接:join into

//11-13
from defect in SampleData.AllDefects
    join subscription in SampleData.AllSubscriptions
        on defect.Project equals subcription.Project
        into groupedSubscriptions
    select new { Defect = defect, Subscriptions = groupedSubscriptions};

group join != group by: 对于分组连接来说,左边序列和结果序列是一对一,左边元素不匹配任何右边元素时,嵌入序列是空的。

=>转译=> .GroupJoin()

交叉连接:cross join

不存在序列间的匹配操作,结果包含了所有可能的元素对。笛卡尔积(cartesian join)

//11-15
from user in SampleData.AllUsers
    from project in SampleData.AllProjects
    select new {User = user, Project = project}
  • 右边序列依赖于左边元素
// 11-16
from left in Enumerable.Range(1, 4)
    from right in Enumerable.Range(11, left)
    select new {Left = left, Right = right};

=>转译=> .SelectMany()

分组和延续:group by, into

group by

键和序列的组合封装于IGrouping<TKey, TElement> : IEnemerable<TElement>中。

// 11-17
from defect in SampleData.AllDefects
            where defect.AssignedTo != null
            group defect by defect.AssignedTo;

=>转译=> .GroupBy()

group by 的投影

//11-18
from defect in SampleData.AllDefects
            where defect.AssignedTo != null
            group defect.Summary by defect.AssignedTo;
  • 所有查询表达式要以select 或者 group by 子句来结尾。

查询延续(query continuations)

  • 把一个查询表达式的结果用作另个一查询表达式的初始序列
  • select / group by + into 引入新的范围变量(清除之前的范围变量,只有在延续中声明的范围变量才能在后续使用)。

Q. find scope of defect, grouped and result

// 11-20 
from defect in SampleData.AllDefects
            where defect.AssignedTo != null
            group defect by defect.AssignedTo into grouped
            select new { Assignee=grouped.Key, 
                         Count=grouped.Count() } into result
            orderby result.Count descending
            select result;

=>转译=>

SampleData.AllDefects
    .Where(defect => defect.AssignedTo != null)
    .GroupBy(defect => defect.AssignedTo)
    .Select(gouped => new { Assignee = grouped.Key,
                            Count = grouped.Count()})
    .OrderByDescending(result => result.Count);

查询表达式和点标记:dot notation

转译成extension method:查询表达式在编译之前,先被转译为普通的C# (查询操作符、点标记:Enumerable中的扩展方法).

查询表达式点标记
-没有相应查询表达式: .Reverse(), .ToDictionary() 等
-特定重载
-自定义比较器
-清晰可读
多个lambda表达式,多个调用:join 的键选择-
排序的多个优先级:orderby f1, f2.OrderBy(f1).ThenBy(f2)
// 在匿名类型中直接使用lambda表达式参数
sequence.Select((Item, Index) => new {Item, Index});

reference

c sharp in depth LINQ to Objects (C#) MSDN

 

 

published in my cs blog: https://sidizhan.github.io/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值