• C# 标准查询表达式


    一、标准查询运算符

    1、C#提供了标准查询运算符,例如我想选择专利一系列(pantents)中以年份19开头的专利,可以用如下语句:

                IEnumerable<Patent>  pantentWhere = pantents.Where(pantent => 
                                                                    pantent.YearOfPublicaton.StartsWith("19"));

    当然,此处的语句只是定义了查询,此时pantentWhere并没有内容,后面Lambda表达式指定的查询并没有执行,只有当遍历pantentWhere集合的时候才开始执行这个查询规则,这是C#中标准查询的“推迟执行”

    2、投射

    专利类包含了 名字  年份  应用号  发明者 等,如果我想将专利类的集合中 每个专利的类型都变为只包含 名字与年份的类型,那么可以使用select做到,代码如下:

    1 var pantentSelect = pantents.Select(
    2                 pantent => 
    3                 { 
    4                     return new 
    5                     { 
    6                         Title = pantent.Title, 
    7                         Year = pantent.YearOfPublicaton 
    8                     }; 
    9                 });

    可以看到,Lambda表达式返回了一个包含 名字与年份的类型。而当遍历pantentSelect时,其投射语句执行,它则是有[(姓名,值),(年份,值)]构成的集合。

    3、排序

    利用标准查询运算符OrderByDescending 与 ThenByDescending 可以完成多条件的排序,代码如下:

    1 IEnumerable<Patent> pantentOrder = pantents.OrderByDescending(pantent => 
    2                                                           pantent.YearOfPublicaton).ThenByDescending(
    3                                                           pantent => pantent.Title);

    可以看到,只用了一个OrderBy,它会获取并且只会获取一个成为KeySelector的参数来排序,例如本例中的YearOfPublicaton。如果要继续按照第二个关键字排序,只能用ThenBy,在OrderBy的基础上执行。而连着使用多个OrderBy只会撤销上一个OrderBy,所以要用ThenBy,而不是继续使用OrderBy。

    此处仅仅简单的列出几项,因为如果执行比较复杂的查询与投射,将会产生比较繁琐难懂的代码。因此,C# 3.0中引入了标准查询表达式,一种更类似于SQL语言的

    二、标准查询表达式

    1、简单示例,下段代码完成的功能是检索出不含有*的单词:

     1 class Program
     2     {
     3         static string[] Keywords = { "*a", "*b", "*c", "*d", "*e", "*f", "a", "b", "c", "d", "e", "f", "g", "h", "i"};
     4         static void Main(string[] args)
     5         {
     6             ShowContextualKeyword1();
     7         }
     8         public static void ShowContextualKeyword1()
     9         {
    10             IEnumerable<string> selection = from word in Keywords
    11                                             where !word.Contains('*')
    12                                             select word;
    13             foreach (string s in selection)
    14             {
    15                 Console.WriteLine(" " + s);
    16             }
    17         }
    18     }

    值得详细说一下的是类型推断:select投射回的是word的集合,word的类型是from后面的那个word,从Keywords推断得到。Keywords是一个string的集合,所以word是string类型,因此select投射到的是IEnumerable<string>

     2、改变返回类型。

    select不仅可以返回原始类型,也可以返回指定的类型,我个人总结的是 他会返回select后面的变量的集合类型。

    如下代码,返回的不是fileName的集合,而是FileInfo的集合:

    1   public static void List1(string rootDirectory, string searchPattern)
    2         {
    3             IEnumerable<FileInfo> files = from fileName in Directory.GetFiles(rootDirectory, searchPattern)
    4                                           select new FileInfo(fileName);
    5             foreach (FileInfo file in files)
    6             {
    7                 Console.WriteLine(".{0}({1})",file.Name,file.LastWriteTime);
    8             }
    9         }

     当然,3.0允许程序员不必显示声明投射的类型,而可以使用匿名类型,如下代码所示:

     1 public static void List2(string rootDirectory, string searchPattern)
     2         {
     3             var files = from fileName in Directory.GetFiles(rootDirectory, searchPattern)
     4                         select new 
     5                         {
     6                             Name = fileName,
     7                             LastWriteTime = File.GetLastWriteTime(fileName)
     8                         };
     9             foreach (var file in files)
    10             {
    11                 Console.WriteLine(".{0}({1})", file.Name, file.LastWriteTime);
    12             }
    13         }

    如果select的原始数据的列特别多,改变投射类型则显得十分有优势,只需选出需要关注的几列即可,而不用全部都检索出来。

    3、筛选(where)

    筛选条件靠断言来表示,即返回布尔值的一个,真就接受,假就放弃。代码如下,功能是筛选出一个月之前修改的文件:

     1  static void FindMonthOldFiles(string rootDirectory, string searchPattern)
     2         {
     3             // 筛选出一个月之前访问的数据
     4             IEnumerable<FileInfo> files = from fileName in Directory.GetFiles(rootDirectory, searchPattern)
     5                                           where File.GetLastWriteTime(fileName) < DateTime.Now.AddMonths(-1)
     6                                           select new FileInfo(fileName);
     7             foreach (FileInfo file in files)
     8             {
     9                 string relativePath = file.FullName.Substring(3);
    10                 Console.WriteLine(".{0}.({1})", relativePath, file.LastWriteTime);
    11             }
    12         }

    4、排序

    下面代码展示了一种排序:首先按照文件名长度降序排序,然后按照文件名升序排序(不显示声明升序还是降序的,默认升序):

     IEnumerable<string> fileNames = from fileName in Directory.GetFiles(rootDirectory,searchPattern)
                                                orderby (new FileInfo(fileName)).Length descending,fileName
                                                select fileName;

    多个排序条件用逗号隔开,重要性依次降低。但是如果我想投射一个FileInfo的集合怎么办呢?可能会有如下代码:

    1             IEnumerable<FileInfo> fileNames = from fileName in Directory.GetFiles(rootDirectory,searchPattern)
    2                                             orderby (new FileInfo(fileName)).Length descending,fileName
    3                                             select new FileInfo(fileName);

    那么问题来了。看第2行与第3行,这样写会每一次访问,都会实例化两个FileInfo,十分浪费系统资源,于是C#3.0隆重推出了let字句。

    5、let子句

    let 子句添加的表达式可以在整个查询表达式的范围内使用,从而避免重复实例化,写法如下:

    1 IEnumerable<FileInfo> fileNames = from fileName in Directory.GetFiles(rootDirectory,searchPattern)
    2                                               let file = new FileInfo(fileName)
    3                                               orderby file.Length descending, fileName
    4                                               select file;

    6、编译

    实际上,使用查询运算符与查询表达式对CIL CLR没有影响,编译器会将查询表达式转化成标准查询运算符。虽然属于语法糖级别的,但是平时尽可能多使用查询表达式,除非在某些特定情况下,再使用标准查询运算符。

  • 相关阅读:
    eclipse发布项目到tomcat部署目录
    变量 声明、存储和范围
    十周 工程2 员工有自己的工资 扩张
    使用Xshell生成key,避免password登录linux
    android模拟器 一个错误:X Error of failed request: BadRequest (invalid request code or no such operation)
    JNI 详细解释
    设计模式(Abstract Factory)抽象工厂
    Laravel创建Model
    【cocos2d-x】3.0使用cocos-console创建,编,部署游戏
    UF访问,一些对用友最新的旗舰级产品U9一些引进(图像)
  • 原文地址:https://www.cnblogs.com/tntboom/p/4145235.html
Copyright © 2020-2023  润新知