当前位置: 亚洲城ca88 > ca88 > 正文

哪些促成,查询表达式

时间:2019-09-27 01:04来源:ca88
LINQ 小编们愿意 LINQ 跟 SQL 同样,也可能有类 select、where、group by、order by 那一个主要字,编写翻译器只要把这几个重大字映射到相应的庞大方法上就行了。 而 LINQ 的最首要字跟 SQL 很像

LINQ

小编们愿意 LINQ 跟 SQL 同样,也可能有类 select、where、group by、order by 那一个主要字,编写翻译器只要把这几个重大字映射到相应的庞大方法上就行了。

而 LINQ 的最首要字跟 SQL 很像,比如 from、where、orderby、descending 和 select 等。

地方的泛型查询,改成 LINQ 如下所示:

var query = from r in champions

            where r.Country == "Brazil"

            orderby r.Wins descending

            select r;

其中,

  • 1,
where r.Country == "Brazil" 

转换成

Where(r=>r.country=="Brazil");
  • 2,
orderby r.Wins descending

转换成

OrderByDescending(r=>r.Wins)
  • 3,
select r

转换成

Select()

LINQ 查询必得以 from 子句初叶,以 selectgroup 子句截至。在那三个子句之间,能够行使 whereorderbyjion 和其他 from 子句。

LINQ 的切切实实用法你就得温馨研商了,不在本文商讨范围内~

看起来好像四个点子在同期运维.那也多亏能够将.NET中的迭代器当作是一类轻量级的协同程序(coroutine)的原因.

引入

借使有一个有关超级方程式赛车季军 Racer 的集合 ,Racer 富含赛车手的姓名、国家、亚军次数等本性,要想对这么些集合操作,比如搜索、排序等等,在 C# 3.0 以前,大家要想明白 Brazil 这个国家的亚军都有哪个人,并且按降序排序,代码如下所示:

IEnumerable<Racer> brazilChampions = champions.Where(

   delegate

   {

       return r.Country == "Brazil";

   }).OrderByDescending(

   delegate

   {

       return r.Wins;

   }).Select(

   delegate

   {

       return r;

   });

其中,champions 是冠军集结。

注意:whereOrderByDescendingSelect 函数都把信托作为函数参数,链式调用最终会回来三个可用 foreach 语句迭代的 IEnumerable 可枚举对象 brazilChampions

即便上边代码看上去还足以,不过,有 delegate 关键字、有情势参数,还非常不足简洁。是不是足以未有那么些啰嗦的事物吗?估摸您也想到了——λ 表明式!代码如下所示:

IEnumerable<Racer> brazilChampions = champions.

   Where(r => r.Country == "Brazil").

   OrderByDescending(r => r.Wins).

   Select(r => r);

嗯,简洁多了~可大家又想了,既然是询问,那能还是不能够像数据库查询那样写个 SQL 语句呢?举例:select from champions t where t.country="Brazil" orderby desc* 或周围方式,SQL 中有谓词~

当然有,这就是 LINQ~

但 LINQ 不是须臾间冒出来的,它有个经过,那也是干什么 LINQ 在 VS 二零零六才出现,并非以前。

问询哪些促成 LINQ,技术越来越好地使用它~

多亏地点这几个特点让那些增添方法能用于编写查询.由此这么些增添方法也称为"查询操作符"

λ 表达式

C# 3.0 引入了一个新的语法——λ 表明式(Lambda 表明式)。λ 演算背后是有数学基础的,也正是说,函数申明,包蕴函数名、形参、再次回到类型等等都以足以未有的,直接函数体。在对泛型集结调用上边自定义的 Where 函数时,就足以那样写:

IEnumerable<Racer> brazilChampions = champions.Where(r => r.Country == "Brazil");

其中,r 并从未定义。那下代码,简洁多了。

近期说了扩张方法和 λ 表明式,现在离 LINQ 近了。

(一) 序列

达成 LINQ 的八个前提

要想领悟 LINQ 是何等促成的,供给知道七个必备的技巧点:扩大方法和 λ 表达式。当然,还论及到泛型委托。

(三) 查询操作符

参照他事他说加以考察资料

  • .NET C# 评释、实例化和行使委托以及委托在 C# 中的发展
  • 并未有 拉姆da 演算何来佚名函数——佚名函数(佚名格局和 Lambda)、委托、LINQ
  • wiki λ演算
  • Database SQL Language Reference
  • .NET Framework System.Array.Sort 演示

下载 Demo

图片 1

推而广之方法

事实上,扩充方法并不目生,作者第贰次注意这么些用法是在 Ext.Net,它的项目里有个工具类程序集。当中的字符串工具类 StringUtils ,如决断字符串是或不是为“空”,无论是 null,依旧长度为 0 都回到 true,进而扩张 .Net 的字符串操作。如下所示 StringUtils 工具类的代码片段:

public static class StringUtils

{

    /// <summary>

    /// Determine is the string is null or empty.

    /// </summary>

    /// <param name="text"></param>

    /// <returns></returns>

    public static bool IsEmpty(this string text)

    {

        return string.IsNullOrEmpty;

    }



    /// <summary>

    /// Determine is the string is NOT null or empty.

    /// </summary>

    /// <param name="text"></param>

    /// <returns></returns>

    public static bool IsNotEmpty(this string text)

    {

        return !text.IsEmpty();

    } 



    ……

    /// <summary>

    /// 

    /// </summary>

    /// <param name="text"></param>

    /// <param name="pattern"></param>

    /// <returns></returns>

    public static bool Test(this string text, string pattern)

    {

        return Regex.IsMatch(text, pattern);

    }



    /// <summary>

    /// 

    /// </summary>

    /// <param name="text"></param>

    /// <param name="pattern"></param>

    /// <param name="options"></param>

    /// <returns></returns>

    public static bool Test(this string text, string pattern, RegexOptions options)

    {

        return Regex.IsMatch(text, pattern, options);

    }

    ……



 }

显著,.Net 未有对字符串提供 IsEmptyTest 方法(其实,.Net 提供了 string.IsNullOrEmpty 方法),但假使在你的程序聚焦定义了这几个类,那么就会在您的代码中对字符串用“.”间接调用这几个方法,如 "helloworld".IsEmpty()

注意,StringUtils 是静态类。静态类首假使为着分享,静态类的分子也无法不是静态的。静态类日常在前后相继加载的时候被组织。静态类能够有构造函数,但只被调用贰次。那样,在您的代码中就无需实例化这么些类,更要紧的是,对函数参数 string 类型使用了 this 关键字。

因为,全数的泛型集结都继承了 IEnumerable<T> 接口那般,大家自定义过滤函数 Where,对 IEnumerable<T> 用扩大方法。如下所示,泛型群集依据钦命条件再次回到切合条件的集合:

public static IEnumerable<T> Where(this IEnumerable<T> source, Func<T, bool> predicate)

{

    foreach (T item in source)

    {

        if (predicate

            yield return item;

    }

}

其中,函数 Where 有多少个参数:三个是带 thisIEnumerable<T>,另叁个是 .net 提供的唯有三个输入参数的带再次回到值的泛型委托 Func<T, TResult>。那样,对别的泛型会集调用 Where 方法都相当于:

champions.Where(Func<T, bool> predicate)

如:

IEnumerable<Racer> brazilChampions = champions.Where(

   delegate

   {

       return r.Country == "Brazil";

   });

既然如此自定义的泛型集合 Where 方法重返了 IEnumerable<T> 类型,大家自然能够再定义三个对泛型集结的排序函数,比方叫 OrderByDescending(this IEnumerable<T> source, Func<T, int> predicate)

因为自定义函数 Where 的归来类型,也是函数 OrderByDescending 的输入类型,所以它们能变成叁个调用链。

援用在此之前LINQ to SQL例子中的代码:

下载 Demo

LINQ查询语句特别注重于推迟查询执行机制,惹是相当不够了这些机制,LINQ的实行功效将会大大减少.

正文内容

  • 引入
  • 福寿康宁 LINQ 的五个前提
    • 扩展方法
    • λ 表达式
  • LINQ
  • 参照他事他说加以考察资料

本文证明 LINQ 是什么兑现的,知道那点,才干更加好地采纳它~

只要您刚接触 LINQ,那么只怕不会那么快就领悟。因为,LINQ 涉及的技术非常多,能够说它是好多本领的集大成者,由此使用 LINQ 必要您对几个知识点有自然认知,包括泛型委托、扩展方法、无名氏函数、λ 表明式(拉姆da 表明式),在此基础上,才可能灵活运用 LINQ。这也是怎么 LINQ 在 VS 二零零六 才现身,并不是以前。

Infiniti是,先读书泛型委托,再经过学习 System.Array 类进步对佚名函数和 λ 表明式的了然。

Func<int,bool> isOdd=i=>(i & 1)==1;

唯独,Lambda表明式也能够以数量的样式利用,那多亏表明式树所须求的.

1    Expression<Func<int, bool>> isOddExpression = i => (i & 1) == 1;
2             Func<int, bool> isOddCompiledExpression = isOddExpression.Compile();

举例上边包车型大巴代码,就回到多少个成团的值.

(四) 查询表明式

咱俩营造一个迭代器的事例,看一看那一个个性.

var res = from n in numbers
                      select Square(n);
Expression<Func<int,bool>> isOdd =i => (i & 1) ==1;

 

透过上表能够见到,不是每三个操作符都有与之对应的C#根本字.在后边那一个轻巧的查询中,大家本来完全能够行使语言商量所提供的要紧字完毕.然而对于那么些比较复杂的询问来讲,大家将不得不直接调用查询操作符完毕.

表达式树将在程序运行中动态构造,不过一旦构造完成,则无法被再次修改.
  • 序列
  • 延期询问实践
  • 查询操作符
  • 查询表达式
  • 表明式树

当编译器看见有些拉姆da表明式赋值给品种为Expression<>的变量时,就能将其编写翻译成一两种工厂方法的调用,这一个工厂方法将要程序运营时动态地布局出表明式树.

 1   private void button2_Click(object sender, EventArgs e)
 2         {
 3             foreach (var m in OneTwoThree())
 4             {
 5                 Console.WriteLine(m);
 6             }
 7         }
 8         static IEnumerable<int> OneTwoThree()
 9         {
10             Console.WriteLine("returning 1");
11             yield return 1;
12             Console.WriteLine("returning 2");
13             yield return 2;
14             Console.WriteLine("returning 3");
15             yield return 3;
16         }

 

 图片 2

询问表达式存在的最要害意义在于,它亦可大大简化查询所急需的代码,并抓实查询语句的可读性(类似熟练的SQL).

运维结果如下:

 

图片 3

与基于IEnumerable<T>的队列相比较, IQueryable<Contact>更抓牢大,因为程序能够依赖公布式树的剖判结果进行智能地管理.通过查阅有些查询的表明式树,编译器就可以智能地拓宽测算并进行多量的优化.IQueryable<Contact>和发布式树的组成将给我们带来更庞大的可定制技能.

地方的表达式树,还是能"逆向"编写翻译成委托方法:

 

这段代码应用扩展方法完毕下边包车型大巴须求:

 

举个例子,上边第1行代码能够用来生成一颗表明式树,因为其包蕴表明式体.

编写翻译器不会把地方的拉姆da表明式换来IL代码,而是会组织出一个树状的,用来表示该表达式的对象.

 

查询表达式是由C#言语提供的语言级本性,一种语法糖,这种语法类似于SQL,它可以操作于三个依然两个数据源之上,并为这么些数据源应用若干个专门的学业如故自定义的查询操作符.在上边的示范代码中,使用了3个正式的询问操作符:Where, orderByDescending以及Select.

地点的这种写法就称为查询表明式,或许查询式语法.

管理IQueryable<Contact>数据与拍卖类别完全分化.IQueryable<Contact>的实例就要经受一棵表明式树,由些深入分析出下一步就要举行的操作.

 

作者们来钻探一下个中的规律:

1   private void button4_Click(object sender, EventArgs e)
2         {
3             int[] numbers = { 1, 2, 3 };
4             var res = from n in numbers
5                       select Square(n);
6             foreach (var m in res.ToList())
7                 Console.WriteLine(m);
8         }

 

Process.GetProcesses()的再次回到值是三个Process的数组,而在C#中,全部数组对象均落到实处了IEnumerable<T>接口.

咱俩来看一下迭代器的背景知识.

1   var res = Process.GetProcesses()
2                 .Where(s => s.WorkingSet64 > 10 * 1024 * 1024)
3                 .OrderByDescending(s => s.WorkingSet64)
4                 .Select(s => new { ID = s.Id, Name = s.ProcessName });

位置的LINQ查询在编写翻译后,实际上成为了如此的:

也正是LINQ查询转为一多级扩大方法的调用,当中的Enumerable.Select方法就是二个迭代器--那也正是其落实了推迟推行的原理.

Func<int,bool> isOdd=i=>(i & 1)==1;

 拉姆da表达式在前头提到过它的非常重要职能之一是贯彻无名氏委托.如下例:

标准查询操作符与查询表明式的涉嫌,见下表所示:

IEnumerable<T>接口之所以首要,是因为 上边代码中的Where, OrderByDescending, Select 等LINQ中的规范查询操作符都亟需运用该类型的对象做为参数.

1  var contacts =
2               from contact in db.GetTable<HelloLinqToSql.Contact>()
3               where contact.City == "武汉"
4               select contact;
5 
6             Console.WriteLine("查找在武汉的联系人" Environment.NewLine);
7             foreach (var contact in contacts)
8                 Console.WriteLine("联系人: "   contact.Name.Trim() " ID:" contact.ContactID);

开往篇的次序是利用查询操作符达成的.再次援用一下:

1   ParameterExpression i = Expression.Parameter(typeof(int), "i");
2             Expression<Func<int, bool>> isOdd =
3                 Expression.Lambda<Func<int, bool>>(
4                 Expression.Equal(
5                 Expression.And(
6                 i,
7                 Expression.Constant(1, typeof(int))),
8                 Expression.Constant(1, typeof(int))),
9                 new ParameterExpression[] { i });

来看一段代码:

实在,表明式树便是一颗抽象语法树(AST).抽象语法树用来表示一段经过解析的代码.在上边例子中,那颗树正是C#对于Lambda表明式解析后的结果.那样做的目标是有益别的代码对该表明式树实行深入分析,并施行一些至关重要的操作.

上边代码所示的 Where,OrderByDescending, Select那一个扩充方法 包罗有共同的性状:

原创小说,出自"天涯论坛, 猪刚鬣'S博客" : 

因为查询表达式最后都会被编写翻译成种种职业操作符的调用.由此要是愿意的话,完全能够只用查询操作符编写全数查询语句,根本不理会查询表明式的存在.

图片 4

1         int[] OneTwoThree()
2         {
3             return new[] { 1, 2, 3 };
4         }

为啥要选用表明式树啊?

结果能够看出,显明该查询并不是二遍性推行完成的.独有在迭代到某一项时,查询才最初求出这一项的值.

在行使查询表达式语法时,编写翻译器会自动将其转会为对标准查询操作符的调用.

在地点代码中,一旦大家开端遍历contacts变量,那么程序就能起来解析内部包罗的表明式树,随后生成SQL语句并推行,最终该SQL语句的回到结果以Contact对象集合的样式给出.

查询操作符是LINQ的着力,以至比语言方面包车型大巴特点(举个例子查询表明式)更首要.

若是大家须要查询强制马上施行,能够通过调用ToList方法来达成.

咱俩把地点的代码改换一下:

我们给出Where扩展方法的贯彻代码:

第2行的就不可能,因为它的本位部分是一个语句.

图片 5

 

能够看出结果就不一致了:

上边包车型客车代码是能够手工编写制定的,可是编写翻译器能够代劳.

笔者们领会使用IEnumerable<T>迭代器能够生出延迟查询的行事,在地点代码中 contacts变量的品种不是IEnumerable<T>,而是IQueryable<Contact>.

最终我们来拜访表达式树施行延迟询问实施的章程:

 1  static double Square(double n)
 2         {
 3             Console.WriteLine("计算 Square("   n   ")...");
 4             return Math.Pow(n, 2);
 5         }
 6         private void button3_Click(object sender, EventArgs e)
 7         {
 8             int[] numbers = { 1, 2, 3 };
 9             var res = from n in numbers
10                       select Square(n);
11             foreach (var m in res)
12                 Console.WriteLine(m);
13         }

(二) 延迟查询施行

其首先参数中的this关键字就注明了它是一个扩大方法,参数类型正是IEnumerable<T>.

(五) 表明式树

另一种语法规让LINQ查询更疑似SQL的查询语句.

 从结果的角度看,迭代器与叁个重返集合数据的观念意识办法未有怎么不相同,因为都以回去按一类别排列的值.

  • 操作于可被迭代的集聚对象之上
  • 同意管道情势的多少管理
  • 信任于推迟施行

1.  IEnumerable<T>接口

关键字yield return 就构成了一个迭代器.

这便是所谓的询问延迟施行的机制在表述成效.

当把代码改成下边这样时,大家就不能以寄托的款型来使用isOdd了.因为在此处isOdd并不是信托,而是个表明式树.

图片 6

 

历次遭逢yield return语句时,该方法都向调用者重返贰个值.

能够看出,函数OneTwoThree直到试行完最终一条语句之后才完全退出.

下图是询问表明式的一体化语法:

先上一段代码,

1   var res = from s in Process.GetProcesses()
2                       where s.WorkingSet64 > 10 * 1024 * 1024
3                       orderby s.WorkingSet64 descending
4                       select new { ID = s.Id, Name = s.ProcessName };

但是须要注意的是:唯有那一个含有表明式体的Lambda表明式能力够用于表明式树.主体部分是语句的拉姆da表明式则并未有像样的补助.

表明式树能够在运作时传递给任何的工具,随后那么些工具得以根据该树发轫执行查询,或然是将其转会为别的形式的代码,举例LINQ to SQL中的SQL语句.

  • 取进度列表,进行过滤(取大于10M的长河)
  • 列表实行排序(按内部存款和储蓄器占用)
  • 只保留列表中钦点的信息(ID,进程名)

    1 var res = Process.GetProcesses() 2 .Where(s => s.WorkingSet64 > 10 1024 1024) 3 .OrderByDescending(s => s.WorkingSet64) 4 .Select(s => new { ID = s.Id, Name = s.ProcessName });

图片 7

能够看看是先获得查询的结果,最后才把结果迭代输出的.

表明式树在第5章中用于创设动态查询这种高端场景上得到了应用.

 1         public static IEnumerable<TSource> Where<TSource>(
 2             this IEnumerable<TSource> source,
 3             Func<TSource, Boolean> predicate)
 4         {
 5             foreach (TSource element in source)
 6             {
 7                 if (predicate(element))
 8                     yield return element;
 9             }
10         }

 

下边包车型大巴表明式树,在内部存款和储蓄器中以树的数据结构存款和储蓄,它意味着深入分析了后的Lambda表明式,如下图:

foreach循环收到那个值后举办了拍卖,然后调控权又交回给迭代器方法OneTwoThree方法,由它交给下三个成分.

 下图是比照操作类型分组的正儿八经查询操作符:

 

唯独,C#中的迭代器的行为却相当特别.迭代器将不会一回性再次来到整个群集中的全体值.而是每一回回去二个.这么的打算收缩了内部存款和储蓄器需要.

在LINQ中, 术语"序列" 就是指所有实现了IEnumerable<T>接口的对象.

 运营结果如下图

那么,上边代码中的Where, OrderByDescending, Select 是何地来的呢? 它们是扩展方法, 基于IEnumerable<T>接口类型的扩展方法.

图片 8

2. 迭代器

那时候,上面的isOddCompiledExpression和下部的委托isOdd就千篇一律了,它们生成的IL代码就从未任何差距了.

上面正是编写翻译器为上述表明式自动生成的代码:

 IEnumerable<double> res = Enumerable.Select<int, double>(numbers, n => Square(n));

那三种代码的写法从语义上来说是一模一样的,而且落成的法力也一致.

 为了能明白知道地点代码的中间动作,大家必要介绍几组概念.

1 Expression<Func<Object, Object>> identity = o=>o;
2 Expression<Func<Object, Object>> identity = o=>{ return o;};

图片 9

编辑:ca88 本文来源:哪些促成,查询表达式

关键词: 亚洲城ca88