zoukankan      html  css  js  c++  java
  • 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没有影响,编译器会将查询表达式转化成标准查询运算符。虽然属于语法糖级别的,但是平时尽可能多使用查询表达式,除非在某些特定情况下,再使用标准查询运算符。

  • 相关阅读:
    基于Metaweblog API 接口一键发布到国内外主流博客平台
    uva144 Student Grants
    Uva 10452
    Uva 439 Knight Moves
    Uva 352 The Seasonal War
    switch语句
    java——基础知识
    我的lua学习2
    codeforces 431 D. Random Task 组合数学
    codeforces 285 D. Permutation Sum 状压 dfs打表
  • 原文地址:https://www.cnblogs.com/tntboom/p/4145235.html
Copyright © 2011-2022 走看看