韩迎龙 发表于 2012-12-10 15:01:23

LINQ学习(扩展方法,委托,Lambda表达式) 第二篇

<div id="cnblogs_post_body">
[*]LINQ基本查询操作符-获取数据
(1) select()语法是:
public static IEnumerable<TResult> select<TSource,TResult>(
   this IEnumerbale<TSource> source.
Func<TSource,TResult> selector)
说明:1) select方法本身是一个泛型扩展方法
2) 它作用于IEnumerable<TSource>类型
3) 他只接受一个Func<TSource,TResult>类型参数
4) Func<TSource,TResult>是一个泛型委托,位于System名字的空间下,System.Core.dll中,在这里Selector是一个提取器。
(2) 举例说明,先定义一个静态类ExtraClass,然后再静态类中在定义一个静态的扩展方法,实现输出信息。代码如下:
public static class ExtraClass
    {
      //为IEnumerable提供输出的方法
      public static void Print(this IEnumerable<string> ie)
      {
            IEnumerator<string> result = ie.GetEnumerator();
            while (result.MoveNext())
            {
                MessageBox.Show(result.Current);
            }
      }
}
然后如图所示,单击图上的按钮事件,在按钮事件中的代码是:
http://pic002.cnblogs.com/images/2012/359161/2012051621281759.png

此事件下面的代码实现了将一个泛型集合中的数据循环显示出来,代码如下:
List<string> persons = new List<string>();
    persons.Add("zhang san");
    persons.Add("zhang san feng");
    persons.Add("li si");
    persons.Add("wang wu");
    persons.Add("wang liu");
    persons.Add("li ba");
    persons.Add("lao wu");
    persons.Add("zhang xx");
    //输出persons里面的所有的元素
    var result = persons.Select(p => p);
result.Print();
执行结果是按顺序循环输出。
2. LINQ基本查询操作符-过滤数据
(1) where() 语法是:
public static IEnumerable<TSource> where<TSource>(
      this IEnumerable<TSource> source,
Func<TSource,bool> predicate)
说明:1) where方法是一个泛型扩展方法
2) 它和select()一样作用与IEnumerable<TSource>类型
3) 它只接受一个Func<TSource,bool>泛型委托参数,在这里predicate是一个判断条件。
(2) 举例说明,还是上面的例子,使用那个泛型集合,实现按照一定的条件输出信息。先创建一个方法,实现输出姓“zhang”的人的信息,代码如下:
public bool Judge(string s)
      {
            if (s.StartsWith("zhang"))
            {
                return true;
            }
            return false;
      }
在select控件的事件下面用LINQ代码输出只是姓张的各种各样的实现代码:
//输出persons里面姓“zhang”的人
   //var result = persons.Where(p => p.StartsWith("zhang"));//第一种方法
   //var result = persons.Select(p => p).Where(p => p.StartsWith("zhang")); //第二种方法
   //var result = persons.Where(p => p.StartsWith("zhang")).Select(p => p);//第三种方法
   var result = persons.Where(p => Judge(p));   //第四种方法
   result.Print();
3. LINQ基本查询操作符-排序数据
(1) OrderBy()语法是:
pblic static IOrderedEnumerable<TSource> orderBy<TSource,TKey>(
      this IEnumerable<TSource> source
       Func<TSource,TKey> keySelector)
注:1) orderBy方法也是一个泛型扩展方法
2) 它和select()一样作用与IEnumerable<TSource>类型
3) 它只接收一个Func<TSource,Tkey>类型参数,在这里keySelctor指定要排序的字段。
4) 如果想要降序排列可以使用orderbyDescending方法。
(2) 举例说明,同上例,实现排序的代码如下:
//var result = persons.OrderBy(p => p);
       //按照名字的最后一个字母排序
       //var result = persons.OrderBy(p => p.Substring(p.Length - 1, 1)).Select(p => p);
       //降序排列
       var result = persons.OrderByDescending(p => p);
       result.Print();

[*]Linq基本查询操作符-分组数据
(1) GroupBy()语法是:
   public static IEnumerable<IGrouping<Tkey,TSource>>
               GroupBy<TSource,TKey>(
                      this IEnumerable<TSource> source,
                      Func<TSource,TKey> keySelector)
说明:1) GroupBy()方式和OrderBy()方式非常类似,它也是一个泛型扩展方法。
2) 它和OrderBy()一样作用与IEnumerable<TSource>类型。
3) 它只接受一个Func<TSource,TKey>类型参数,在这里keySelector指定要分组的字段。
(2) 举例说明,同上例,实现分组的代码是:
//分组---按照姓名来分组¦--取出姓名中的空格前的部分
   var result = persons.GroupBy(p => p.Split(new char[] { ' ' }));
    foreach (var group in result)
    {
         Console.WriteLine("姓:" + group.Key);
         foreach (var name in group)
          {
               Console.WriteLine("\t" + name);
          }
          Console.WriteLine();
   }

[*]查询执行的时机
(1) 从前面的试验中,我们发现一次查询实际上经过以下3步。
1) 第一步:获取数据源int[] numbers=new int[]{3,45,65,76,2,434,54,65,76,76,65,43};
2) 第二步:定义查询var even=numbers.Where(p=>p%2==0).Select(p=>{
Console.WriteLine(“Hi!”+p.ToString());
return p;   });
3) 第三步:执行查询   foreach(var item in even){   }

[*]查询执行的时机小节
(1) 查询分为以下三步,获取数据源,定义查询,执行查询
(2) 定义查询后,查询直到需要枚举结果时才被真正执行,这种方法称为”延迟执行”。
(3) 当查询结果返回单一值时,查询立即执行。举例,如代码:
         //查询时机---当返回值为单值时马上执行语句,负责延迟执行
      var result = persons.Select(p => p).Count();
      Console.WriteLine("个数是" + result);
(4) 因此,可以通过以下技巧在定义查询时就强制执行查询

[*]Linq查询的两种方式
(1) Method syntax,查询方法方式
主要利用System.Linq.Enumerable类中定义的扩展方法和Lambda表达式方式进行查询。
(2) Query syntax ,查询语句方式

[*]查询语句VS查询方法
注:查询语句和查询方法存在着紧密的关系
(1) CLR本身并不理解查询语句,它只理解查询方法。
(2) 编译器负责在编译时将查询语句翻译为查询方法。
(3) 大部分查询方法都有对应的查询语句形式,如:Select()对应select,OrderBy()对应orderby。
(4)部分查询方法目前在C#中还没有对应的查询语句:如:Count()和Max()这时只能采用以下替代方案
1) 查询方法
2) 查询语句+查询方法的混合方式
(5) 一般情况下,建议使用可读性更好的查询语句。举例说明:
还是用上面多定义的泛型集合数组persons,用查询语句实现几个简单的功能,代码如下:
//输出persons中的所有的元素
var result = from p in persons select p;
    //输出persons中姓zhang的人----语句和方法的混合编排?
   var result = (from p in persons select p).Where(p => p.StartsWith("zhang"));
   //排序
      var result = from p in persons orderby p select p;
      result.Print();

[*]高级查询方法
(1) 聚合类Count(),Max()/Min(),Average(),Sum()。举例说明:
重新定义一个数组来实现上面的各种各样的方法,代码如下:
   //LINQ to Objects查询高级方法
      //数组数据arr
      int[] arr = { 23, 34, 5, 5, 23, 45, 65, 33, 43, 76, 67, 87 };
      //聚合类
      Console.WriteLine("arr的最大值: + arr.Max());
      Console.WriteLine("arr的最小值¦: " + arr.Min());
      Console.WriteLine("arr的平均值¦: " + arr.Average());
      Console.WriteLine("arr的数组元素个是" + arr.Count());
      Console.WriteLine("arr的总和是: " + arr.Sum());
(2) 排序类thenBy()代码如下:
      //排序类
      var result = arr.OrderBy(p => p.ToString().Substring(0, 1));
      //2次排序混编模式没有达到要求
      var result = arr.OrderBy(p => p.ToString().Substring(0, 1)).ThenBy(p => p);
      //按照语句排序
      var t = arr.OrderBy(p => p.ToString().Substring(0, 1));
      var result = from p in t orderby p descending select p;
(3) 分区类Take,TakeWhile,Skip,SkipWhile   代码如下:
      //分区类
      var result = arr.Skip(3).Take(3);//跳过三个值取三个值
      var result = arr.Skip(3);//跳过几个值
var result = arr.SkipWhile(p => p > 4); //方法体部分是该Linq语句不在往后执行的条件,当第一次遇到条件成立时,取剩下的所有元素
      var result = arr.TakeWhile(p => p > 4); //方法体部分是该Linq语句提取数据的条件,当第一次遇到条件不成立的情况就停止执行
(4) 集合类   Distinct   代码如下:
      //集合类
      var result = arr.Distinct();
(5) 生成类   Range,Repeat   代码如下:
      //生成类-----静态类
       var result = System.Linq.Enumerable.Range(10, 50);
       var result = System.Linq.Enumerable.Range('a', 50); //生成连续的序列
       var result = System.Linq.Enumerable.Repeat(40, 10);
       result.Print();

[*]生成类查询方法小结
注:使用生成类查询方法时,需要注意以下几点:
(1) 和其它几类方法不同,Range/Repeat不是扩展方法,而是普通的静态方法
(2) Range只能产生整数序列。
(3) Repeat可以产生泛型序列。
(4) 所有的查询方法都存放在System.Linq.Enumerable静态类中。
页: [1]
查看完整版本: LINQ学习(扩展方法,委托,Lambda表达式) 第二篇