zoukankan      html  css  js  c++  java
  • Linq 查询的演变过程

    Linq查询

    1.linq简介

      说起Linq,相信大家都不陌生吧,因为在我们的C#开发中,Linq无处不在,Linq给我们带来了极大的便捷。.Net 3.0后,Linq横空出世,为我们带来极大的方便。

      Linq查询主要包含两个方面的内容:Linq to Object和Linq to sql

      笔者常用到的就是Linq to Object,Linq to sql接触的较少,还需接下来花时间学习。

      我们在使用Linq过程中,有没有考虑过Linq是怎么产生的呢?

    2.Linq to object演变

    假如我们现在有一个下面代码所示的LIST<Student>集合

    static void Initlist(out List<student> ListStu)
            {
                ListStu = new List<student>();
                student s = new student { Name = "张三", Sex = "", Age = 20 };
                ListStu.Add(s);
                student s1 = new student { Name = "李四", Sex = "", Age = 20 };
                student s2 = new student { Name = "王五", Sex = "", Age = 21 };
                student s3 = new student { Name = "刘一", Sex = "", Age = 22 };
                student s4 = new student { Name = "赵重", Sex = "", Age = 23 };
                student s5 = new student { Name = "李玉", Sex = "", Age = 24 };
                ListStu.Add(s1);
                ListStu.Add(s2);
                ListStu.Add(s3);
                ListStu.Add(s4);
                ListStu.Add(s5);
            }

    现在我们有下面三个要求:

    1.选出年龄大于21岁的

    2.选出年龄大于20的

    3.选出年龄小于22的

    看了题目要求,我们有很多方法来实现,我们先看看最基础的foreach遍历,如下所示

     //1.选出年龄大于21岁的
                {
                    foreach (student item in ListStu)
                    {
                        if (item.Age > 21)
                        {
                            result.Add(item);
                        }
                    }
                }
                //2.选出年龄大于20的
                {
                    foreach (student item in ListStu)
                    {
                        if (item.Age > 20)
                        {
                            result.Add(item);
                        }
                    }
                }
                //3.选出年龄小于22的
                {
                    foreach (student item in ListStu)
                    {
                        if (item.Age < 22)
                        {
                            result.Add(item);
                        }
                    }
                }

    从以上代码,我们可以看出,要实现这三个要求,并不困难。不过我们仔细观察代码,这是典型的复制粘贴编码,我们的三个要求分别写了一个代码逻辑,这就会造成代码冗余,不便于今后维护。我们可以想想,现在才三个条件,随着需求的变更,我们的代码逻辑要不断复制粘贴修改,那有什么办法可以消除冗余呢?

    观察以上代码,我们不难看出,三个foreach循环唯一的不同就是if条件逻辑不一样,其他都一样的。为了实现代码复用,我们此时可以考虑把if判断逻辑作为方法参数传入,利用委托就可以实现代码复用。为了增强代码的复用性,我们可以把类型泛型化。具体代码实现如下所示:

    public static class ExtendClass
        {
            /// <summary>
            /// 泛型化方法
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="list"></param>
            /// <param name="fun"></param>
            /// <returns></returns>
            public static List<T> ThemeWhere<T>(this List<T> list,Func<T,bool> fun)
            {
                List<T> result = new List<T>();
                
                foreach (T item in list)
                {
                    bool b = fun.Invoke(item);
                    if (b)
                    {
                        result.Add(item);
                    }
                }
                return result;
            }
    }

    在上述代码中,我们把类似if (item.Age > 21) 这样的条件逻辑,作为参数传递进去,在方法里面通过fun.Invoke(item)方法就可调用判断逻辑,实现代码复用。实现要求的三个条件,我们现在可以写成如下代码:

              //1.选出年龄大于21岁的
                    var list1 = ListStu.ThemeWhere(p => p.Age > 21);
                    //2.选出年龄大于20的
                    var list2 = ListStu.ThemeWhere(p => p.Age > 20);
                    //3.选出年龄小于22的
                    var list3 = ListStu.ThemeWhere(p => p.Age < 22);

    这样一来,代码是不是简介了很多,也便于今后维护,如果我们今后逻辑修改了,只需修改传入逻辑即可。

    不难看出,ListStu.ThemeWhere(p => p.Age > 21);这个方法的使用是不是类似我们使用linq的where方法(ListStu.where(p => p.Age > 21));

    通过反编译工具,我们可以看到LINQ的where方法定义如下所示(有改动):

    public static IEnumerable<TSource> Where <TSource>(this IEnumerable<TSource> source,Func<TSource,bool> pre)
            {
                
                foreach (var item in source)
                {
                    if (pre.Invoke(item))
                    {
                        yield return item; //延迟查询(只有返回类型是IEnumerable,才可以用yield迭代器)
                    }
                }
            }

    是不是觉得很类似,只不过linq.where是通过yield迭代器返回结果的,注意只有返回类型是IEnumerable,才可以用yield迭代器。

    使用迭代器yield和直接return有什么区别呢?

    yield是延迟查询,使用到哪一个数据,就返回哪一个数据。

    而直接return的话,是一次性查询出所有数据返回。

                var listStu1 = ListStu.ThemeWhere(p=>p.Age>21);
                        var listStu2 = ListStu.MyWhere(p => p.Age > 21);//foreach 每次循环才会调用where筛选,如果foreach里面终止循环,那where这里也不在进行筛选
                        foreach (var item in listStu1)
                        {
                            Console.WriteLine(string.Format(item.Name+","+item.Age+","+item.Sex));
                            Console.WriteLine(string.Format("**********************************"));
                        }
                        foreach (var item in listStu2)
                        {
                            Console.WriteLine(string.Format(item.Name+","+item.Age+","+item.Sex));
                            
                        }

    运行代码后我们会发现listStu1打印是一次性打印完成,listStu2打印是foreach循环一次,where执行一次筛选打印。这样的好处就是,我们在foreach里面break后,where查询不会再继续下去

    注意:

    Linq to object 出现在实现IEnumerable类中,只能操作内存数据,用的是Lamda方法。

    3.Linq to Sql 简介

    Linq to sql 主要出现在操作IQueryable数据,使用的是lanmda表达式目录树。操作的是数据库的数据,里面封装了ADO .Net的操作,不同的sql语句通过表达式目录树拼凑出来。通过传入lanmda表达式就能完成对数据库的操作。

    Linq to sql 目前还在学习中,目前了解的只有这些

    以上就是我对Linq学习的一些新得,如有不正确之处,望批评指正。

  • 相关阅读:
    graalvm 内置require 模块的开启
    Calling out from Java to JavaScript (with call back) – leveraging interoperability support of GraalVM
    web开发 api 资源跨域的一种实践
    使用rollup 转换commonjs 模块为es6 模块,方便的支持graalvm 模块兼容
    使用json-mask 查询json 数据
    nginx njs docker 试用
    使用nginx-prometheus-exporter 监控nginx
    wso2 关于graphql 的方案
    docker也一直发展
    操作系统-容器-Docker:如何将应用打包成为 Docker 镜像?
  • 原文地址:https://www.cnblogs.com/zxwDont/p/11634804.html
Copyright © 2011-2022 走看看