C#使用LINQ查询表达式的基本子句总结

LINQ查询表达式的基本语法很容易掌握,它使用C#常见的语言构造,从外观上看,和我们常用的SQL类似,并且查询表达式中的变量可以用匿名类型,所以在很多情况下,不需要指定变量类型就可以构建LINQ表达式。

LINQ的数据源可以是数据库对象或是XML流等,也可以使实现了IEnumerable或者泛型IEnumberable<T>接口的集合对象。

LINQ的基本语法包含如下的8个上下文关键字,这些关键字和具体的说明如下:

关键字 说明
from 指定范围变量和数据源
where 根据bool表达式从数据源中筛选数据
select 指定查询结果中的元素所具有的类型或表现形式
group 对查询结果按照键值进行分组(IGrouping<TKey,TElement>)
into 提供一个标识符,它可以充当对join、group或select子句结果的引用
orderby 对查询出的元素进行排序(ascending/descending)
join 按照两个指定匹配条件来Equals连接两个数据源
let 产生一个用于存储查询表达式中的子表达式查询结果的范围变量

下面依此总结这8个关键字的常用查询语句写法。

1.from子句
如果要写一个LINQ表达式,就必须是以from子句开头。个人觉得from子句中需要注意的地方就是多个from子句的书写。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace LINQ
{
  /// <summary>
  /// LINQ,重点是感悟from子句中的查询变量的灵活
  /// </summary>
  class Program
  {
    static void Main(string[] args)
    {
      //1单个form子句
      string[] values = { "LINQ学习","LINQ基本语句","from子句","单个from子句"};
      var value = from v in values
            where v.IndexOf("LINQ") > -1
            select new { v, v.Length };
      foreach (var n in value)
      {
        Console.WriteLine("{0},{1}",n.v,n.Length );
      }
      Console.ReadKey(false);
      //2使用LINQ查询ArrayList
      ArrayList gList = new ArrayList();
      gList.Add(new GustInfo { Name="DebugLZQ", Age=26, Tel="88888888"});
      gList.Add(new GustInfo { Name="博客园",Age=6, Tel ="666666"});
      gList.Add(new GustInfo { Name = "M&MSoft", Age =9, Tel = "55555" });

      var query = from GustInfo gust in gList
            where gust.Age > 9
            select gust;//范围变量gust制定了数据类型
      foreach (GustInfo g in query)
      {
        Console.WriteLine("{0} 年龄:{1} 电话:{2}",g.Name,g.Age,g.Tel );
      }
      Console.ReadKey(false);
      //3复合from子句
      List<GustInfo2> gList2 = new List<GustInfo2>()
      {
        new GustInfo2{ Name="DebugLZQ",Age=26,TelTable=new List<string>(){"8888888","138******"}},
        new GustInfo2{ Name="博客园",Age=6,TelTable =new List<string>(){"666666","138******"}},
        new GustInfo2{ Name="M&MSoft",Age=9,TelTable=new List<string>(){"55555","138******"}}
      };

      //gust、tel都是查询变量,作用域为当前查询语句!!!
      var query2 = from gust in gList2
             from tel in gust.TelTable
             where tel.IndexOf("5555") > -1
             select gust;
      foreach (var g in query2)
      {
        Console.WriteLine("{0} 年龄{1}",g.Name,g.Age );
        foreach (var t in g.TelTable)
        {
          Console.WriteLine("电话:{0}",t);
        }
      }

      Console.ReadKey(false);

      //4多个from子句
      var query3 = from GustInfo gust in gList
             where gust.Age > 6
             from GustInfo2 gust2 in gList2
             where gust2.Age> 9
             select new { gust, gust2 };//查询结果定制
      foreach (var g in query3)
      {
        Console.WriteLine("{0} {1}", g.gust.Name, g.gust2.Name);
      }

      Console.ReadKey(false);
    }
  }
}

程序的运行结果如下:

程序中列举了from子句的用法示例,注意复合from子句和多个from子句的书写,同时需要理解范围变量和数据源变量这两个概念。

 2.where子句
where子句,它是LINQ表达式的元素筛选机制,除了开始和结束的位置,它几乎可以出现在LINQ表达式的任意位置上。

在一个LINQ表达式中,可以有where子句,也可以没有;可以有一个,也可以有多个;多个where子句之间的逻辑关系相当于逻辑“与”,每个where子句可以包含1个或多个bool逻辑表达式,这些条件成为谓词,谓词逻辑之间用的是“&&”“||”等而不是SQL中的and 、or。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_WHERE
{
  /// <summary>
  /// LINQ where子句
  /// </summary>
  class Program
  {
    static void Main(string[] args)
    {
      //1常见的where语句
      List<GustInfo> gList = new List<GustInfo>()
      {
        new GustInfo(){ Name="DebugLZQ", Age=26,Tel="88888888"},
        new GustInfo(){ Name="cnblogs",Age=6,Tel="666666"},
        new GustInfo(){ Name="M&MSoft",Age=9,Tel="55555"}
      };

      var query = from gust in gList
            where (gust.Name.Length > 7 || gust.Name.Substring(0, 1) == "M") && gust.Age > 9
            select new { gust.Name, gust.Age };
      foreach (var g in query)
      {
        Console.WriteLine("{0},{1}", g.Name, g.Age);
      }

      Console.ReadKey(false);

      //2.在where子句中使用自定义函数
      var query2 = from GustInfo gust in gList
             where gust.Name.Length > 5
             && Check(gust.Name)
             select gust;
      foreach (var g in query2)
      {
        Console.WriteLine("{0},{1},{2}", g.Name, g.Age, g.Tel);
      }
      Console.ReadKey(false);

      //3.动态谓词的筛选
      //定义动态谓词数组,在实际开发中可以动态获得
      string[] names = { "SB","XXX","***","@@@","一些敏感词"};

      var query3 = from GustInfo guest in gList
             where !names.Contains(guest.Name)
             select guest;

      foreach (var q in query3)
      {
        Console.WriteLine("{0} 年龄:{1},电话:{2}",q.Name,q.Age,q.Tel );
      }
      Console.ReadKey(false);
    }

    //自定义函数
    static bool Check(string name)
    {
      if (name.Substring(0, 1) == "N")
        return false;
      return true;
    }
  }
}

需要注意一些常用的where子句的写法。程序的运行结果如下:

3.Select子句
在select子句上可以非常灵活的处理查询到的元素,然后再把结果返回。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_select
{
  /// <summary>
  /// LINQ select
  /// 在select子句上,可以非常灵活的处理查询到的元素,然后再把结果返回
  /// </summary>
  class MyGustInfo
  {
    public string Name { get; set; }
    public int Age { get; set; }
  }
  class Program
  {
    static void Main(string[] args)
    {
      List<GustInfo> gList = new List<GustInfo>()
      {
        new GustInfo(){ Name="DebugLZQ", Age=25, Tel="88888888"},
         new GustInfo(){ Name="cnblogs", Age=6, Tel="666666"},
         new GustInfo(){ Name="M&M", Age=9, Tel="55555"}
      };
      var query = from gust in gList
            where gust.Age >= 9 && gust.Age <= 30
            select gust.Name.Replace("&", "mm");//select子句灵活应用
      var query2 = from gust in gList
             where gust.Age >= 9 && gust.Age <= 30
             select MyProc(gust.Name);
      var query3 = from gust in gList
             where gust.Age >= 9 && gust.Age <= 30
             select new { gust.Name,gust.Age};

      var query4 = from gust in gList
             where gust.Age >= 9 && gust.Age <= 30
             select new MyGustInfo { Name=gust.Name+"My", Age=gust.Age+1};//对查询结果进行投影

      foreach (var v in query)
      {
        Console.WriteLine(v);
      }
      foreach (var v in query2)
      {
        Console.WriteLine(v);
      }
      foreach (var v in query3)
      {
        Console.WriteLine(v.Name+v.Age );
      }
      foreach (var v in query4)
      {
        Console.WriteLine(v.Name+v.Age );
      }

      Console.ReadKey(false);
    }
    static string MyProc(string s)
    {
      return s + "Better";
    }
  }
}

程序的运行结果如下:

 4.group子句
 根据语法的规定,LINQ表达式必须以from子句开头,以select或group子句结束,所以除了使用select来返回结果外,也可以使用group子句来返回元素分组后的结果。

group子句返回的是一个基于IGrouping<TKey,TElement>泛型接口的对象序列。

语法和SQL的group有点区别,不注意的话可能会写错。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_group
{
  /// <summary>
  /// LINQ group子句
  /// </summary>
  class Program
  {
    static void Main(string[] args)
    {
      List<GustInfo> gList = new List<GustInfo>()
      {
        new GustInfo(){ Name="DebugLZQ",Age=26,Tel="187********"},
        new GustInfo(){ Name="Sarah",Age=25,Tel="159********"},
        new GustInfo(){ Name="Jerry",Age=35,Tel="135********"},
        new GustInfo(){ Name="M&M",Age=16,Tel="136********"},
        new GustInfo(){ Name="DebugMan",Age=26,Tel="136********"},
        new GustInfo(){ Name="Jerry&Tom",Age=19,Tel="136********"},
      };

      var query = from guest in gList
            group guest by guest.Name.Substring(0, 1);//分组键key是string类型

      //遍历键值和键值所属元素
      foreach (IGrouping<string, GustInfo> guestGroup in query)
      {
        Console.WriteLine("分组键:{0}",guestGroup.Key );
        foreach (var g in guestGroup)
        {
          Console.WriteLine("{0} 年龄:{1} 电话:{2}",g.Name,g.Age,g.Tel );
        }
      }
      Console.ReadKey(false);

      Console.WriteLine("-----------------------------------");

      var query2 = from guest in gList
             group guest by guest.Age > 20;//分组键key是bool类型表达式的结果

      foreach (IGrouping<bool, GustInfo> guestGroup in query2)
      {
        Console.WriteLine("年龄是否大于20 分组键:{0}", guestGroup.Key);
        foreach (var g in guestGroup)
        {
          Console.WriteLine("{0} 年龄:{1} 电话:{2}", g.Name, g.Age, g.Tel);
        }
      }
      Console.ReadKey(false);
    }
  }
}

程序的运行结果如下:

5.into子句
 into子句作为一个临时标识符,用于group、select、join子句中充当其结果的引用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_into
{
  /// <summary>
  /// LINQ group
  /// </summary>
  class Program
  {
    static void Main(string[] args)
    {
      List<GustInfo> gList = new List<GustInfo>()
      {
        new GustInfo(){ Name="DebugLZQ",Age=26,Tel="187********"},
        new GustInfo(){ Name="Sarah",Age=25,Tel="159********"},
        new GustInfo(){ Name="Jerry",Age=35,Tel="135********"},
        new GustInfo(){ Name="M&M",Age=16,Tel="136********"},
        new GustInfo(){ Name="DebugMan",Age=26,Tel="136********"},
        new GustInfo(){ Name="Jerry&Tom",Age=19,Tel="136********"},
      };

      //1.into用于group子句
      var query = from guest in gList
            group guest by guest.Name.Substring(0, 1) into grguest
            orderby grguest.Key descending
            select grguest;

      var query2 = from guest in gList
            group guest by guest.Name.Substring(0, 1) into grguest
            orderby grguest.Key ascending
            select grguest;

      //2.select 子句中的into子句
      var query3 = from guest in gList
             select new { NewName = guest.Name, NewAge = guest.Age } into newguest
             orderby newguest.NewAge
             select newguest;

      foreach (var guestGroup in query)
      {
        Console.WriteLine("分组键:{0}",guestGroup.Key );
        foreach (var g in guestGroup)
        {
          Console.WriteLine("{0} 电话:{1}",g.Name,g.Tel );
        }
      }
      Console.ReadKey(false);

      foreach (var newg in query3)
      {
        Console.WriteLine("{0} 年龄:{1}",newg.NewName,newg.NewAge );
      }

      Console.ReadKey(false);
    }
  }
}

程序运行结果如下:

6.orderby子句、thenby子句
 LINQ可以按照元素的一个或多个属性对元素进行排序。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_orderby
{
  class Program
  {
    /// <summary>
    /// LINQ orderby (ascending descending)
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {
      List<GustInfo> gList = new List<GustInfo>()
      {
        new GustInfo(){ Name="DebugLZQ",Age=26,Tel="187********"},
        new GustInfo(){ Name="Sarah",Age=25,Tel="159********"},
        new GustInfo(){ Name="Jerry",Age=35,Tel="135********"},
        new GustInfo(){ Name="M&M",Age=16,Tel="136********"},
        new GustInfo(){ Name="DebugMan",Age=26,Tel="136********"},
        new GustInfo(){ Name="Jerry&Tom",Age=19,Tel="136********"},
      };

      //按照年龄排序
      var query = from guest in gList
            orderby guest.Age
            select guest;
      var query1 = from guest in gList
             orderby guest.Age ascending
             select guest;
      var query2 = from guest in gList
             orderby guest.Age descending
             select guest;
      //按照年龄进行排序,按照名字字数进行次要排序
      var query3 = from guest in gList
            orderby guest.Age, guest.Name.Length
            select guest;
      var query4 = from guest in gList
             orderby guest.Age descending , guest.Name.Length ascending
             select guest;
      var query5 = from guest in gList
             orderby guest.Age, guest.Name.Length,guest.Tel
             select guest;

      foreach (var guest in query2)
      {
        Console.WriteLine("{0} 年龄:{1} 电话:{2}",guest.Name,guest.Age,guest.Tel );
      }
      Console.ReadKey(false);
      foreach (var guest in query4)
      {
        Console.WriteLine("{0} 年龄:{1} 电话:{2}", guest.Name, guest.Age, guest.Tel);
      }
      Console.ReadKey(false);
    }
  }
}

程序运行结果如下:

7.let子句
let子句用于在LINQ表达式中存储子表达式的计算结果。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_let
{
  /// <summary>
  /// LINQ let用来存子储表达式的计算结果
  /// </summary>
  class Program
  {
    static void Main(string[] args)
    {
      List<GustInfo> gList = new List<GustInfo>()
      {
        new GustInfo(){ Name="DebugLZQ",Age=26,Tel="187********"},
        new GustInfo(){ Name="Sarah",Age=25,Tel="159********"},
        new GustInfo(){ Name="Jerry",Age=35,Tel="135********"},
        new GustInfo(){ Name="M&M",Age=16,Tel="136********"},
        new GustInfo(){ Name="DebugMan",Age=26,Tel="136********"},
        new GustInfo(){ Name="Jerry&Tom",Age=19,Tel="136********"},
      };

      //使用let子句创建范围变量g,并通过g构建查询表达式
      var query = from guest in gList
            let g = guest.Name.Substring(0, 1)
            where g == "D" || g == "J"
            select guest;
      //也可以不使用let,上面的语句等效于下
      var query2 = from guest in gList
             where guest.Name.Substring(0, 1) == "D" || guest.Name.Substring(0, 1) == "J"
             select guest;

      foreach (var g in query)
      {
        Console.WriteLine("{0} 年龄:{1} 电话:{2}",g.Name,g.Age,g.Tel );
      }
      Console.ReadKey(false);
      Console.WriteLine("不使用let,等效的语句结果");
      foreach (var g in query2)
      {
        Console.WriteLine("{0} 年龄:{1} 电话:{2}", g.Name, g.Age, g.Tel);
      }
      Console.ReadKey(false);
    }
  }
}

程序的运行结果如下:

8.join子句
如果一个数据源中元素的某个属性可以跟另外一个数据源的中元素的某个属性进行相等比较,那么这两个数据源可以用join子句进行关联。

join子句使用equals关键字进行相等比较,而不是常用的双等号。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_join
{
  class Program
  {
    static void Main(string[] args)
    {
      //定义两个数据源
      List<GustInfo> gList = new List<GustInfo>()
      {
        new GustInfo(){ Name="DebugLZQ",Age=26,Tel="187********"},
        new GustInfo(){ Name="Sarah",Age=25,Tel="159********"},
        new GustInfo(){ Name="Jerry",Age=35,Tel="135********"},
        new GustInfo(){ Name="M&M",Age=16,Tel="136********"},
        new GustInfo(){ Name="DebugMan",Age=26,Tel="136********"},
        new GustInfo(){ Name="Jerry&Tom",Age=19,Tel="136********"},
      };

      List<GuestTitle> titleList = new List<GuestTitle>()
      {
        new GuestTitle(){Name="DebugLZQ",Title="Soft Engineer"},
        new GuestTitle(){Name="DebugLZQ",Title="Team Leader"},
        new GuestTitle(){Name="Sarah",Title="Test Engineer"},
        new GuestTitle(){Name="Jerry",Title="Head Master"}
      };
      //1.根据姓名进行内连接
      var query = from guest in gList
            join title in titleList on guest.Name equals title.Name
            select new { Name=guest.Name ,Title=title.Title,Age=guest.Age };

      foreach (var g in query)
      {
        Console.WriteLine("{0} {1} 年龄:{2}",g.Name,g.Title ,g.Age );
      }
      Console.ReadKey(false);

      //前面的多个from实现相同的作用:与内连接区别在于:这个中间的操作是叉乘获得笛卡尔积
      var query2=from guest in gList
            from title in titleList
            where guest.Name==title.Name
            select new { Name = guest.Name, Title = title.Title, Age = guest.Age };

      foreach (var g in query2)
      {
        Console.WriteLine("{0} {1} 年龄:{2}", g.Name, g.Title, g.Age);
      }
      Console.ReadKey(false);

      //2.根据姓名进行分组连接
      //根据名字分组后,得到每个名字下的全部名称
      var query3 = from guest in gList
             join title in titleList on guest.Name equals title.Name into tgroup
             select new { Name=guest.Name,Titles=tgroup };

      foreach (var g in query3)
      {
        Console.WriteLine(g.Name);
        foreach (var g2 in g.Titles)
        {
          Console.WriteLine("  {0}",g2.Title );
        }
      }
      Console.ReadKey(false);
      //3.根据姓名进行左外连接
      //无职务的输出为空缺
      var query4 = from guest in gList
             join title in titleList on guest.Name equals title.Name into tgroup
             from subtitle in tgroup.DefaultIfEmpty()
             select new { Name=guest.Name,Title=subtitle==null?"空缺":subtitle.Title };
      foreach (var g in query4)
      {
        Console.WriteLine("{0} {1} ",g.Name ,g.Title );
      }
      Console.ReadKey(false);

    }
  }
}

程序结果如下:

以上就是LINQ的基本子句的常用用法,文字不是很多,因为代码中都有详细的注释说明。

(0)

相关推荐

  • 浅谈C#2.0泛型中的变化:default关键字

    今天回答别人问题的时候,才发现原先的T.default语法被取消了,使用了新的default关键字来实现这一功能.还好回复前动手试了一下,不然就... 下面详细说明一下.之所以会用到default关键字,是因为需要在不知道类型参数为值类型还是引用类型的情况下,为对象实例赋初值.考虑以下代码: 复制代码 代码如下: class TestDefault<T>    {        public T foo()        {            T t = null; //???      

  • 探秘C# 6.0 的新特性

    C# 6.0 中的新特性 我们可以对这些新特性一个一个的进行讨论,而首先要列出 C# 6.0 中这些特性的一个清单 自动的属性初始化器 Auto Property Initializer 主构造器 Primary Consturctor 字典初始化器 Dictionary Initializer 声明表达式 Declaration Expression 静态的Using Static Using catch 块中的 await 异常过滤器 Exception Filter 用于检查NULL值的条

  • C#4.0新特性之协变与逆变实例分析

    本文实例讲述了C#4.0新特性的协变与逆变,有助于大家进一步掌握C#4.0程序设计.具体分析如下: 一.C#3.0以前的协变与逆变 如果你是第一次听说这个两个词,别担心,他们其实很常见.C#4.0中的协变与逆变(Covariance and contravariance)有了进一步的完善,主要是两种运行时的(隐式)泛型类型参数转换.简单来讲,所谓协变(Covariance)是指把类型从"小"升到"大",比如从子类升级到父类:逆变则是指从"大"变到

  • 深入C# 4.0 新特性dynamic、可选参数、命名参数的详细介绍

    1.dynamic ExpandoObject熟悉js的朋友都知道js可以这么写 : 复制代码 代码如下: var t = new Object(); t.Abc = 'something'; t.Value = 243; 现在这个js动态语言的特性,我们也可以在c#中使用了,前提是将一个变量声明为ExpandoObject类型.如下例: 复制代码 代码如下: static void Main(string[] args) { dynamic t = new ExpandoObject(); t

  • C#中WinForm程序退出方法技巧总结

    本文实例总结了C#中WinForm程序退出方法技巧.分享给大家供大家参考.具体分析如下: 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.ExitThread(); System.Environment.Exit(0); 等他们各自的方法不一样,下面我们就来详细介绍一下. 1.this.Close();   只是关闭当前窗口,若不是主窗体的话,是无法退出程序的,另外若有托管线程(非主线程),也无法干净地退

  • C#配置文件Section节点处理总结

    本文实例总结了C#配置文件Section节点处理方法.分享给大家供大家参考.具体如下: 很多时候在项目开发中,我们都需要用配置文件来存储一些关于程序配置信息,这时候你可以选择INI或者app.config来存储,这里对此总结一下: 配置文件示例如下: 复制代码 代码如下: <?xml version="1.0" encoding="utf-8" ?> <configuration>   <configSections>     &

  • C#6.0中10大新特性的应用和总结

    微软于2015年7月21日发布了Visual Studio 2015, .NET 2015, .NET Framework 4.6, ASP.NET 4.6, Azure SDK 2.7 for .NET, C# 6.0, F# 4.0, TypeScript 1.5, Visual Studio Android 模拟器 等重量级开发产品. 由于项目升级到了.NetFramework 4.6.1,开发工具转向了VS2015,趁机尝试下C#6.0.结果网上的教程不进人意,许久都没有更新,只好自己做

  • C#提高编程能力的50个要点总结

    本文总结了C#提高编程能力的50个要点.分享给大家供大家参考,具体如下: 1.总是用属性 (Property) 来代替可访问的数据成员 2.在  readonly 和 const 之间,优先使用 readonly 3.在 as 和 强制类型转换之间,优先使用 as 操作符 4.使用条件属性 (Conditional Attributes) 来代替条件编译语句 #if 5.总是为自定义类重载 ToString 方法 6.区别值类型和引用类型 7.使用不可变的值类型(Immutable Atomic

  • C# WinForm应用程序降低系统内存占用方法总结

    背景: 微软的 .NET FRAMEWORK 现在可谓如火如荼了.但是,.NET 一直所为人诟病的就是"胃口太大",狂吃内存,虽然微软声称 GC 的功能和智能化都很高,但是内存的回收问题,一直存在困扰,尤其是 winform 程序,其主要原因是因为.NET程序在启动时,是需要由JIT动态编译并加载的,这个加载会把所有需要的资源都加载进来,很多资源是只有启动时才用的. 以XP 系统为例子,程序启动后,打开任务管理器,会看到占用的内存量比较大,你把程序最小化,会发现该程序占用的内存迅速减小

  • C#字符串的截取函数用法总结

    本文实例总结了C#常用的字符串截取函数用法.分享给大家供大家参考.具体分析如下: 在C#中字符串截取函数包括有substring 函数,Remove 函数,indexOf 函数,它们三个都可以对字符串进行截取操作,下面我们来分别介绍一下. 下面是截取字符串过程中我们必须知道的以下函数:substring 函数.Remove 函数.indexOf函数. substring 函数: 返回第一个参数中从第二个参数指定的位置开始.第三个参数指定的长度的子字符串. 如果未指定第三个参数,将返回从第二个参数

随机推荐