Lession12-LINQ

LINQ简介

 /*
     * 查询是一种从数据源检索数据的表达式。 查询通常用专门的查询语言来表示。 随着时间的推移,
     * 人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。
     * 因此,开发人员对于他们必须支持的每种数据源或数据格式,都不得不学习一种新的查询语言。 
     * LINQ 通过提供处理各种数据源和数据格式的数据的一致模型,简化了这一情况。 在 LINQ 查询中,
     * 始终会用到对象。 可以使用相同的基本编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、
     * .NET 集合中的数据以及 LINQ 提供程序可用的任何其他格式的数据。
     * 
     * Linq to object (数组、list集合)--内存里面的数据
     * Linq to sql (查询数据用的)--在数据库数据
     * Linq to Xml  查询XML文件
     * 
     * 所有 LINQ 查询操作都由以下三个不同的操作组成:
     *  1.获取数据源。
     *  2.创建查询。
     *  3.执行查询
     *  
     *  1.LINQ查询表达式
     *  
     *  from i in list
     *                  where i < 10
     *                  orderby i
     *                  select i;
     *子句中from,where,orderby selece关键字都是linq预定义的关键字
     *所有的Linq查询表达式都必须以from子句开始,以select或者group 子句结束
     *在开头和结束子句之间,可以使用where,orderby join等其他from子句
     *
     *Linq查询表达式开头的from子句用于指定数据源 格式:
     *from [单个数据源元素] in [数据源]
     *
     *linq查询表达式结束的select子句用于指定返回的目标数据。格式:
     *select[目标元素]
     *
     *  
     *  
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            #region linq查询表达式
            //练习1 数组
            //Array
            //获取数组数据源
            int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
          

            //创建查询
            IEnumerable<int> numQuery =
                 from num in numbers
                 where (num % 2) == 0
                 select num;   //用于指定返回的目标数据
               
            //执行查询
            foreach (int num in numQuery)
            {
                Console.WriteLine("{0}", num);
            }

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

            //list数据源 List<int>数据类型,实现了IEnumerable<T>接口,所以可以使用Linq
            List<int> list = new List<int> { 1, 2, 4, 3, 9, 5, 43, 21 };
            var _list = from i in list
                        where i < 10
                        orderby i
                        select i;
            foreach (var item in _list)
            {
                Console.WriteLine( item);
            }

            #endregion


            Console.ReadKey();

        }
    }

编写一个扩展方法

/*
     * 扩展方法
     * 静态类里的静态方法,参数列表最前面加个this+要扩展到的类型
     * 使用场景:在不修改源码的情况下为其他类型修改方法
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            Cal cal = new Cal();
            Console.WriteLine(cal.AddNew(1, 2, 4));
            Console.ReadKey();
        }
    }

    public class Cal
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
        //public int Add(int a, int b, int c)
        //{
        //    return a + b + c;
        //}
    }

    static class CalExtend
    {
        public static int AddNew(this Cal cal,int a,int b,int c)
        {
            return a + b + c;
        }
    }


LINQ查询方法

 /*
     * public static IEnumerable<TSource> Where<TSource>
     * (this IEnumerable<TSource> source, Func<TSource, bool> predicate);
     * 
     * Func<TSource, bool>:是一个委托,此委托返回类型是bool,传入的参数数据类型为数据源中元素的数据类型
     * Where(i => i < 10):这是lambda表达式,传入的参数为TSource类型的参数为i ,如果i满足小于10返回true,则保留元素
     * 返回false,即将元素过滤
     * 
     * 扩展方法
     * 静态类里的静态方法,参数列表最前面加个this+要扩展到的类型
     * 使用场景:在不修改源码的情况下为其他类型修改方法
     * 
     */

    class Program
    {
        static void Main(string[] args)
        {
            //数据源
            List<int> list = new List<int> { 1, 2, 4, 3, 9, 5, 43, 21 };
            var _list = list.Where(i => i < 10).OrderBy(i => i);
            foreach (var item in _list)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();
        }
    }

LINQ查询的延迟加载

 /*
     * 虽然我们往list里面添加了两个新的元素,但是没有对_list进行操作
     * 如果LINQ查询是将结果查询到后,存储在_list指向的内存中,那么两次遍历结果应该一样
     * 但两个遍历结果却不同 这是为什么?
     * 我们可以将LINQ查询仅仅理解成一个表达式,编译的时候它被存于程序集中,程序运行时,它并没有被拿去执行对数据源的查询
     * 而是当我们去遍历或者读取数据结果时,这个表达式才会被执行去查询数据源,这也就是所谓的查询延迟加载
     * 
     * 只有当foreach的时候,才会逐个返回结果中的元素
     * 因为类似Where的Linq操作,不是在内存里重新开辟内存存放结果,而是只保存了查询的命令,
     * 这样我们可以在后面继续增加新的命令形成一系列的组合操作,不至于每次查询都浪费资源生成新的中间结果。
     * 
     * 当我们对查询结果进一步调用ToArray()、ToList()方法后,返回的数组或者集合会丧失延迟加载的特征
     * 因为这个两个操作会在内存在开辟空间,并需要将查询结果存入内存中
     * ToList()之后,LINQ查询被执行了,查询到的结果被存储在了内存中,成为了新的数据源
     * 
     * 然而,也有少数的Linq命令是即时加载的,比如Count、First、Last等方法。因为这些方法本身就涉及到了遍历各个元素,
     * 既然内部需要foreach遍历,自然就不是延迟加载了。
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            List<int> list = new List<int> { 1, 2, 4, 3, 9, 5, 43, 21 };
            var _list = list.Where(i => i < 10).OrderBy(i => i);
            //var _list = list.Where(i => i < 10).OrderBy(i => i).ToList();
            Console.WriteLine("第一次遍历_list");
            foreach (var item in _list)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("-----------------------------");
            list.Add(8);
            list.Add(6);
            Console.WriteLine("第二次遍历_list");
            foreach (var item in _list)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();

        }
    }

Linq标准查询操作符

 class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person("贾宝玉", 16);
            Person p2 = new Person("林黛玉", 15);
            Person p3 = new Person("薛宝钗", 15);
            Person p4 = new Person("王熙凤", 22);

            List<Person> list = new List<Person>() { p1, p2, p3, p4 };
            List<string> listName = list.Where(p => p.Age > 15) //过滤掉年龄不超过15岁的人
                .OrderByDescending(p => p.Age)//按照年龄的降序排列
                .Select(p => p.Name)//将查询结果投射成名字
                .ToList(); //将结果转成集合
            Console.WriteLine($"年龄超过15岁的共有{listName.Count()}人,按年龄由大到小进行排序结果如下:");
            //遍历集合
            foreach (var name in listName)
            {
                Console.WriteLine(name);
            }
            Console.WriteLine("--------------------------------");
            Console.WriteLine($"所有4个人的平均年龄是{list.Average(p=>p.Age)}岁");
            Console.WriteLine($"所有4个人的总年龄是{list.Sum(p => p.Age)}岁");
            Console.WriteLine($"所有4个人的年龄最大的{list.Max(p => p.Age)}岁");

            Console.WriteLine("-----------------------------------------");
            //获取唯一一个年龄大于16岁的人,如果多个会抛出异常
            Person pUpper16 = list.Single(p => p.Age > 16);
            Console.WriteLine($"唯一一个年龄大于16岁的是{pUpper16.Age}岁的{pUpper16.Name}");
            Console.ReadKey();

        }
    }

    public class Person
    {
        public Person(string name,int age)
        {
            Name = name;
            Age = age;
        }
       
        public string Name { get; set; }
        public int Age { get; set; }
    }

LinqToXML

?xml version="1.0" encoding="utf-8" ?> 
<!-- xml 可扩展的标记语言 解决HTML不可扩展的问题,作用:保存或传输数据,不是用来显示数据的。-->
<Hopu>
  <Specialty SpecialtyName="1">
    <Class>物联网1班</Class>
    <Class>物联网2班</Class>
  </Specialty>
  <Specialty SpecialtyName="2">
    <Class>云计算1班</Class>
    <Class>云计算2班</Class>
  </Specialty>
  <Specialty SpecialtyName="3">
    <Class>电商1班</Class>
    <Class>电商2班</Class>
    <Class>电商3班</Class>
    <Class>电商4班</Class>
  </Specialty>

</Hopu>

 /*
     * 我们对XML文件使用LINQ查询操作符,它使用的语法和我们之前对泛型集合进行的LINQ查询使用了where(),select()方法
     * 语法风格一致
     * 但Attribute()和Descendants()方法,时XML的LINQ查询特有的,它们位于System.Xml.Linq命名空间下,需要引入
     * 
     * 
     * 
     */
    class Program
    {
        static void Main(string[] args)
        {
            //加载xml文件,引入命名空间
            XElement root = XElement.Load(@"myxml.xml");
            //使用LINQ查询表达式
            //[speʃəlti]
            var specialties = from specialty in root.Elements("Specialty")
                              where specialty.Attribute("SpecialtyName").Value == "1"
                              select specialty;
            foreach (var item in specialties)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("-------------------");
            //使用LINQ查询方法Descentdants() [dɪˈsent] 获取所有子代元素
            var classes = specialties.Where(s => s.Attribute("SpecialtyName").Value == "1").Descendants();

            foreach (var item in classes)
            {
                Console.WriteLine(item);
            }


            Console.ReadKey();

        }
    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容