LINQ基础(一)

LINQ介绍

   在讨论LINQ之前,首先要了解一下序列,它是LINQ的基础。序列就像是数据项的传送带---你每次只能获取到它们一个,直到你不再想获取数据,或者序列中没有数据了。它通过IEnumerable和Ienumerable<T>接口进行封装。
   序列和其他集合数据结构(比如列表和数组)之间最大的区别就是,当你从序列中读取数据的时候,通常不知道还有多少数据项等待读取,或者不能访问任意的数据项---只能是当前的这个。实际上,一些序列永远不会结束:例如,你能轻易地拥有一个随机数的无限序列。列表和数组也能作为序列,因为List<T>实现了Ienumerable<T>---不过,反过来并不总是可行。比如,你不能拥有一个无限的数组或列表。
   接下来通过一个简单的例子来分析一下:
var adultNames= from person in people
                where person.Age>=18
                select person.Name;
   上面这个操作首先会从people中 得到所有的person对象,然后根据where后面的条件得到年龄至少为18的所有person对象,最后从中获取年龄至少为18岁的人的名字列表。

LINQ的延迟处理和流处理

   上面的查询表达式被创建的时候,不会处理任何数据,也不会访问原始的人员列表。而是在内存中生成了这个查询的表达形式。判断是否为成人的谓词,以及人到人名的转换,都是通过委托实例来表示的。只有在访问结果Ienumerable<string>的第一个元素的时候,整个车轮才开始向前滚动。 LINQ的这个特点称为延迟执行。在最终结果的第一个元素被访问的时候,Select转换才会为它的第一个元素调用Where转换。而Where转换会访问列表中的第一个元素,检查这个谓词是否匹配,并把这个元素返回给Select。最后,依次提取出名称作为结果返回。

LINQ的简单使用

  声明一个数据序列的数据源:
 from element in source
   element只是一个标识符,它前面可以放置一个类型名称。大多数情况下,你都不需要类型名称。source是一个普通的表达式。
   在第一个子句出现之后,许多不同的事情会发生,不过迟早都会以一个select子句或者group子句来结束。select子句的语法入下:
 select expression
   select 子句被称为投影。group子句下面再介绍。
   在LINQ中,从数据源中根据条件获取数据会写成:from ... Where...select而不会像SQL中的select...from...where。

2、Cast、OfType和显示类型的范围变量

   Cast和OfType操作符很相似:都可以处理任意非类型化的序列(它们是非泛型IEnumerable类的扩展方法),并返回强类型的序列。Cast通过把每个元素都转换为目标类型(遇到不是正确类型的任何元素的时候,就会出错)来处理,而OfType首先进行一个测试,以跳过任何具有错误类型的元素。例如:
  ArrayList list=new ArrayList{"First","Second","Third"};
  Ienumerable<string> strings=list.Cast<String>();
  foreach(string item in strings)
  {
     Consolt.WriteLine(item);
  }

  list=new ArrayList{1,"not an int",2,3};
  Ienumerable<int> ints=list.OfType<int>();
  foreach(int item in ints)
  {
    Console.WriteLint(item);
  }
   第一个列表只包含字符串,所以可以放心使用Cast<string>来获得一个字符串序列。第2个列表包含混杂的内容,为了从中只获取整数,我们只能使用OfType<int>。如果我们在第二个列表上使用Cast<int>时,在尝试将“not an int”转换成int的时候,就会抛出一个异常。不过,这个异常只会发生在打印出“1”之后---两个操作符都对数据进行流处理,在获取元素的时候才对其进行转换。
   在原来的.NET 3.5中,允许执行的转换很多,但是.NET 3.5 SP1修改了Cast的行为,只允许进行一致性转换。例如:在.NET3.5 中允许对List<short>使用Cast<int>将每个short转换成int,而在SP1中,这样将会抛出异常。如果需要引用转换和拆箱转换(或非操作的一致性转换)之外的转换,可以使用select投影。OfType也只能执行这些转换,不过失败时它不会抛出异常。下面使用显示类型的范围变量来自动调用Cast:
ArrayList list=new ArrayList{"First","second","third"};
var strings=from string entry in list
            select entry.Substring(0,3);
foreach(string start in strings)
{
    Console.WriteLine(start);
}
   上面的代码将输出:Fir 、sec、thi,上面的代码通过转译过的查询表达式如下:
list.Cast<string>().Select(entry=>entry.Substring(0,3));
   没有这个类型转换,我们根本不能调用Select,因为该扩展方法只用于Ienumerable<T>而不能用于IEnumrable。即使使用了强类型集合,你可能还是想使用显示类型的范围变量。

总结

对上面的代码总结来说:
1.LINQ以数据序列为基础,在任何可能的地方都进行流处理。
2.创建一个查询并不会立即执行它:大部分操作都会延迟执行。
3.C#3的查询表达式包括一个把表达式转换为普通C#代码的预处理阶段,接着使用类型推断、重载、Lambda表达式等这些常规的规则来恰当地对转换后的代码进行编译。
4.在查询表达式中声明的变量的作用:它们仅仅是范围变量,通过它们你可以在查询表达式内部一致地引用数据。

来自:深入理解C#(第三版)

猜你喜欢

转载自blog.csdn.net/qq_25407771/article/details/77620265