C#8.0本质论第十五章--支持标准查询操作的集合接口

C#8.0本质论第十五章–支持标准查询操作的集合接口

集合在C#3.0中通过称为语言集成查询(Language Integrated Query, LINQ)的一套编程API进行了大刀阔斧的改革。通过一系列扩展方法和Lambda表达式,LINQ提供了一套功能超凡的API来操纵集合。本章重点是标准查询操作符,它通过直接调用扩展方法来发挥Linq的作用。

15.1集合初始化器

集合初始化器(collection initializers)允许采用和数组声明相似的方式,在集合实例化期间用一组初始成员构造该集合。也和对象初始化器的语法相似,都是在构造函数调用的后面添加一对大括号,再在大括号内添加初始化列表。应用集合初始化器的集合类型应实现ICollection< T >接口确保集合包含Add()方法。

public static void Main()
{
    List<string> sevenWorldBlunders;
    sevenWorldBlunders = new List<string>()
    {
        // Quotes from Gandhi
        "Wealth without work",
        "Pleasure without conscience",
        "Knowledge without character",
        "Commerce without morality",
        "Science without humanity",
        "Worship without sacrifice",
        "Politics without principle"
    };

    Print(sevenWorldBlunders);
}

15.2IEnumerable使类成为集合

"运行时"根本不知foreach为何物。C#编译器会对代码进行必要的转换。

15.2.1foreach之于数组
int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
foreach(int item in array)
{
    Console.WriteLine(item);
}

C#编译器在生成CIL时,为这段代码创建了一个等价的for循环

int[] tempArray;
int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
 
tempArray = array;
for(int counter = 0; (counter < tempArray.Length); counter++)
{
    int item = tempArray[counter];
 
    Console.WriteLine(item);
}
15.2.2基于IEnumerable遍历集合

迭代器(iterator)模式应运而生。只要能确定第一个和下一个元素,就不需要事先知道元素总数,也不需要按索引获取元素。

while(stack.MoveNext())
{   
    number = stack.Current();
    Console.WriteLine(number);
}

上面代码的问题在于,如同时又两个循环交错遍历同一个集合,则集合必须维持当前元素的一个状态指示器,交错的循环可能相互干扰。为解决该问题,集合类不直接支持IEnumerator接口,而是支持IEnumerable接口,唯一的方法就是GetEnumerator()。不是由集合类来维持状态,相反,是由一个不同的类来支持IEnumerator接口,并负责维护循环遍历的状态。

C#编译器不要求一定要实现IEnumerable才能对一个数据类型进行遍历。相反,编译器采用称为"Duck typing"的概念,也就是查找会返回“包含Current属性和MoveNext方法的一个类型“的GetEnumerator()方法。Duck typing按名称查找方法,而不依赖接口或显示方法调用。当Duck typing找不到枚举模式的恰当实现时,编译器才会检查集合是否实现了接口。

15.2.3foerach循环内不要修改

15.3标准查询操作符

IEnumerable上的每个方法都是标准查询操作符,用于为所操作的集合提供查询功能。

15.3.1使用Where()来赛选

获取一个实参并返回Boolean值的委托表达式称为谓词(predicate)。从技术上说,Where()方法的结果是一个对象,它封装了根据一个给定谓词对一个给定序列进行筛选的操作。表达式传给集合,”保存“起来但不马上执行。

15.3.2使用Select()来投射
15.3.3使用Count()对元素进行计数
15.3.4推迟执行
15.3.5使用OrderBy()和ThenBy来排序
15.3.6使用Join()执行内部联结
15.3.7使用GroupJoin实现"一对多"关系
15.3.8调用SelectMany()
15.3.9更多标准查询操作符

15.4匿名类型之于LINQ

C#3.0通过LINQ显著增强了集合处理。其中两处增强是匿名类型和隐式局部遍历。但随着C#7.0元组语法的发布,匿名类终于也要”功成身退“了。如果不用C#7.0或更高版本,仍然可以了解一下匿名类型。

15.4.1匿名类型

匿名类型是编译器声明的数据类型,而不是显示的类定义来声明。

        var patent1 =
            new
            {
                Title = "Bifocals",
                YearOfPublication = "1784"
            };
        var patent2 =
            new
            {
                Title = "Phonograph",
                YearOfPublication = "1877"
            };
        var patent3 =
            new
            {
                patent1.Title,
                // Renamed to show property naming
                Year = patent1.YearOfPublication
            };

匿名类型存粹是一项C#语言功能,不是"运行时"中的新类型。编译器遇到匿名类型时,会自动生成CIL代码,其属性对应于在匿名类型声明中声明的值和数据类型。

15.4.2用LINQ投射成匿名类型
IEnumerable<string> fileList = Directory.EnumerateFiles(
    rootDirectory, searchPattern);
var items = fileList.Select(
    file =>
    {
        FileInfo fileInfo = new(file);
        return new
        {
            FileName = fileInfo.Name,
            Size = fileInfo.Length
        };
    });
15.4.3匿名类型和隐式局部变量的更多注意事项
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值