欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C#之LINQ学习笔记

程序员文章站 2022-07-04 08:47:06
...

C#之LINQ学习笔记

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Linq
{
    class Program
    {
        delegate void NoReturnNoPara();//无返回值无参数委托类型
        delegate void NoReturnWithPara(int x, int y);//无返回值有参数委托类型
        delegate int WithReturnWithPara(int x, int y);//有返回值有参数委托类型

        static void Main(string[] args)
        {
            LambdaShow();//Lambda表达式
            AnonymousClassShow();//匿名类
            ExtendFunc();//扩展方法
            LinqShow();//Linq方法
            
            Console.ReadKey();
        }
        #region 基础知识
        /// <summary>
        /// Lambda表达式
        /// </summary>
        static void LambdaShow()
        {
            {//委托的实例化
                NoReturnNoPara method = new NoReturnNoPara(Dothing);
                method.Invoke();
            }
            {//匿名方法
                NoReturnNoPara method = new NoReturnNoPara(delegate ()
                {
                    Console.WriteLine("This is Dothing");
                });
                method.Invoke();
            }
            {//Lambda  左边是参数列表,中间=>是goes to,有边是方法体,本质是一个方法
                NoReturnNoPara method = new NoReturnNoPara(() =>
                {
                    Console.WriteLine("This is Dothing");
                });
                method.Invoke();
            }
            {//带参数
                NoReturnWithPara method = new NoReturnWithPara((int x, int y) =>
                {
                    Console.WriteLine("This is Dothing");
                });
                method.Invoke(1, 2);
            }
            {//带参数,省略参数类型
                NoReturnWithPara method = new NoReturnWithPara((x, y) =>
                {
                    Console.WriteLine("This is Dothing");
                });
                method.Invoke(1, 2);
            }
            {//方法体只有一行时可以省略大括号
                NoReturnWithPara method = new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
                method.Invoke(1, 2);
            }
            {//实例委托时可以省略:new NoReturnWithPara,编译器自动推算
                NoReturnWithPara method = ((x, y) => Console.WriteLine("This is Dothing"));
                method.Invoke(1, 2);
            }//Lambda表达式是什么?
            //首先不是委托,委托是类型
            //然后也不是委托的实例,因为这里省略new 委托()
            //它的作用和方法是一样的
            //它的实质是一个类中类的internal方法,被绑定的一个静态的委托类型字段
            {
                NoReturnWithPara Method = new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
                Method += new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
                Method -= new NoReturnWithPara((x, y) => Console.WriteLine("This is Dothing"));
                Method.Invoke(1, 2);//会执行两次,-=无法去掉已经注册的方法,以为new创建的两个对象虽然相同,但不是同一个

            }
        }

        /// <summary>
        /// 匿名类
        /// </summary>
        static void AnonymousClassShow()
        {
            //匿名类
            object oModel = new
            {
                Id = 2,
                Name = "undefined",
                Age = 25,
                ClassId = 2
            };
            //Console.WriteLine(oModel.Id);object编译器不允许,无法直接访问,通过反射访问
            Type oType = oModel.GetType();
            PropertyInfo propertyInfo = oType.GetProperty("Id");
            Console.WriteLine(propertyInfo.GetValue(oModel));
            //propertyInfo.SetValue(oModel, 3);//匿名类是只读,无法写入
            dynamic dModel = new//dynamic可以避开编译器的检查,可以直接访问
            {
                Id = 2,
                Name = "undefined",
                Age = 25,
                ClassId = 2
            };
            //dModel.Id = 3;//实例是只读,所以不能赋值
            Console.WriteLine(dModel.Id);
            var varModel = new//编译后是有一个真实的类,可以直接访问,但类的字段都是只读
            {
                Id = 2,
                Name = "undefined",
                Age = 25,
                ClassId = 2
            };
            //varModel.Id = 3;//实例是只读,所以不能赋值
            Console.WriteLine(varModel.Id);

            int i2 = 2;
            var i1 = 1;//var是语法糖,由编译器自动推算类似
            var ss = "superman";
            //var aa;//var必须在声明的时候就确定类型
            //ss = 123;//确定类型后不能更改

            //var、object和dynamic的区别:
            //var是推算出来的类型,可能是任意一种类型。
            //object是一种确定的类型,它是所有类型的基类
            //dynamic是一个复杂类型,在编译的时候不知道它是什么类型,它只是避开编译器检查,如果失败就会报错。
        }

        /// <summary>
        /// 扩展方法
        /// </summary>
        static void ExtendFunc()
        {
            Student student = new Student()
            {
                Id = 1,
                ClassId = 1,
                Name = "xiaoming",
                Age = 22,
            };
            student.Study();
            student.StudyHard();
            //又要增加方法,又不能修改类时,采用扩展方法,使用别人的库文件时
            student.Sing();//调用扩展方法
            ExtendMethod.Sing(student);//普通的调用静态方法
            //泛型扩展方法
            student.ExtendShow();
            //重复扩展方法,编译无错,调用错误:二义性

            //没有扩展属性,partial类可以扩展属性

            //int? 可空类型
            int? iValue1 = null;
            int? iValue = 2;
            int value=iValue1.ToInt();
            int length = iValue.Length();
        }
        static void Dothing()
        {
            Console.WriteLine("This is Dothing");
        }

        #region  Linq

        #region  Data Init
        /// <summary>
        /// 构造一个Student类对象的List
        /// </summary>
        /// <returns></returns>
        public static List<Student> GetStudentList()
        {
            List<Student> list = new List<Student>()
            {
                new Student
                {
                    Id=1,
                    ClassId=1,
                    Name="xiaoming",
                    Age=24
                },
                new Student
                {
                    Id=2,
                    ClassId=2,
                    Name="xiaofang",
                    Age=34
                },
                new Student
                {
                    Id=3,
                    ClassId=3,
                    Name="xiaohua",
                    Age=33
                },
                new Student
                {
                    Id=4,
                    ClassId=4,
                    Name="xiaojia",
                    Age=27
                },
                new Student
                {
                    Id=5,
                    ClassId=5,
                    Name="xiaocheng",
                    Age=33
                },
                new Student
                {
                    Id=6,
                    ClassId=6,
                    Name="xiaofu",
                    Age=27
                },
            };
            return list;
        }
        #endregion
        public static void LinqShow()
        {
            List<Student> studentList = GetStudentList();
            {//常规情况下过滤数据
                var list = new List<Student>();
                foreach (var item in studentList)
                {
                    //Thread.Sleep(500);
                    Console.WriteLine("判断数据");
                    if (item.Age < 30)
                    {
                        list.Add(item);
                    }
                }
            }

            #region  Linq To Object(Enumerable)
            {//采用Linq方法
                //使用Student类型的扩展方法
                var result = studentList.CgcWhere(s => s.Age < 30);//陈述式语法,CgcWhere扩展方法
                //使用泛型扩展方法GenericCgcWhere
                new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.GenericCgcWhere(i => i < 5);
                //使用迭代器的扩展方法
                var result1 = studentList.YieldCgcWhere(s =>
                  {
                      Console.WriteLine("判断数据");
                      //Thread.Sleep(500);
                      return s.Age < 30;
                  });//在这里并不会执行扩展方法
                foreach(var item in result1)
                {
                    Console.WriteLine(item);
                }//只有在使用时才去执行扩展方法
            }
            {//Where:完成对数据集合的过滤,通过委托封装完成通用代码,泛型+迭代器去提供特性
                var linq = studentList.Where(s =>
                  {
                      Console.WriteLine("判断数据");
                      //Thread.Sleep(500);
                      return s.Age < 30;
                  });
            }
            {
                //Select:完成对数据集合的转换,通过委托封装完成通用代码,泛型+迭代器去提供特性
                var linq = studentList.
                    Where(s =>
                {
                    Console.WriteLine("判断数据");
                    //Thread.Sleep(500);
                    return s.Age < 30;
                })
                .Select<Student, int>(s => s.Name.Length);
            }
            {
                //Select:完成对数据集合的转换,通过委托封装完成通用代码,泛型+迭代器去提供特性
                var linq = studentList
                    .Where(s =>
                    {
                        Console.WriteLine("判断数据");
                        //Thread.Sleep(500);
                        return s.Age < 30;
                    })
                    .Select(s => new
                    {
                        Id=s.Id,
                        Name=s.Name,
                        Length=s.Name.Length
                    });
                foreach(var item in linq)
                {
                    //item.Id;
                    //item.Name;
                }
            }
            {
                //Min/Max/OrderBy/GroupBy等:完成对数据集合的转换,通过委托封装完成通用代码,泛型+迭代器(有些没有)去提供特性
                {
                    Console.WriteLine("********Ling To Object********");
                    var list = studentList.Where<Student>(s => s.Age < 30);
                    foreach (var item in list)
                        Console.WriteLine("Name={0} Age={1}", item.Name, item.Age);
                }
                {
                    Console.WriteLine("与上面的效果一致");
                    var list = from s in studentList
                               where s.Age < 30
                               select s;
                    foreach (var item in list)
                        Console.WriteLine("Name={0} Age={1}", item.Name, item.Age);
                }
                {
                    Console.WriteLine("投影,转换成一个新的对象");
                    var list = studentList.Where(s => s.Age < 30).Select(s => new
                    {
                        IdName = s.Id + s.Name,
                        ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                    });
                    foreach (var item in list)
                        Console.WriteLine("IdName={0} ClassName={1}", item.IdName, item.ClassName);
                }
                {
                    Console.WriteLine("与上一个相同");
                    var list = from s in studentList
                               where s.Age < 30
                               select new
                               {
                                   IdName = s.Id + s.Name,
                                   ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                               };
                    foreach (var item in list)
                        Console.WriteLine("IdName={0} ClassName={1}", item.IdName, item.ClassName);
                }
                {
                    Console.WriteLine("条件筛选");
                    var list = studentList.Where(s => s.Age < 80).Select(s => new
                    {
                        Id = s.Id,
                        ClassId = s.ClassId,
                        IdName = s.Id + s.Name,
                        ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                    }).OrderBy(s => s.Id)//递增排序
                    .OrderByDescending(s => s.ClassId)//递减排序
                    .Skip(2)//跳过几条,之前需要先排序
                    .Take(3);//获取几条,之前需要先排序
                    foreach (var item in list)
                        Console.WriteLine("IdName={0} ClassName={1}", item.IdName, item.ClassName);
                }
                {
                    Console.WriteLine("GroupBy");
                    var list = from s in studentList
                               where s.Age < 80
                               group s by s.ClassId into sg
                               select new
                               {
                                   key = sg.Key,
                                   maxAge = sg.Max(t => t.Age)
                               };
                    foreach (var item in list)
                        Console.WriteLine($"key={item.key} ClassName={item.maxAge}");
                }
                List<Class> classList = new List<Class>()
                {
                    new Class()
                    {
                        Id=1,
                        ClassName="初级班"
                    },
                    new Class()
                    {
                        Id=2,
                        ClassName="高级班"
                    },
                    new Class()
                    {
                         Id=3,
                        ClassName="网络班"
                    },
                };

                {
                    Console.WriteLine("关联表:关键字形式");
                    var list = from s in studentList
                               join c in classList on s.ClassId equals c.Id
                               select new
                               {
                                   Name = s.Name,
                                   ClassName = c.ClassName
                               };
                    foreach (var item in list)
                        Console.WriteLine($"Name={item.Name},ClassName={item.ClassName}");
                }
                {
                    Console.WriteLine("关联表:扩展方法形式");
                    var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
                    {
                        Name = s.Name,
                        ClassName = c.ClassName
                    });
                    foreach (var item in list)
                        Console.WriteLine($"Name={item.Name} ClassName={item.ClassName}");
                }
                {
                    Console.WriteLine("左连接:关键字形式");
                    var list = from s in studentList
                               join c in classList on s.ClassId equals c.Id
                               into scList
                               from sc in scList.DefaultIfEmpty()
                               select new
                               {
                                   Name = s.Name,
                                   ClassName = sc == null ? "无班级" : sc.ClassName//c变sc,为空则用
                               };
                    foreach (var item in list)
                        Console.WriteLine($"Name={item.Name}  ClassName={item.ClassName}");
                }
                //右连接则将s和c的位置交换一下即可,没有右连接的写法形式
                {
                    Console.WriteLine("左连接:扩展方法形式");
                    var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
                    {
                        Name = s.Name,
                        ClassName = c.ClassName
                    });
                    foreach (var item in list)
                        Console.WriteLine($"Name={item.Name}  ClassName={item.ClassName}");
                }
                //以上的关键字编译后都变成了扩展方法形式,相当于关键字其实是语法糖,由编译器提供的

                int? value = null;//可空类型:指向Nullable<int>,与int相比是另一种类型
                int value1 = default(int);//默认值为0
                int? value2 = default(int?);//默认值为null
                int? value3 = 3;
                int? value4 = new int?(3);
                int? value5 = new Nullable<int>(3);
                int value6 = (int)value4;//int?转换为int
                int sum = value1 + (int)value3;
                int? sum1 = value1 + value3;
                value1 = 5;
                value3 = null;
                int? sum2 = value1 + value3;//任何int值与值为null的int?运算结果为null  
            }
        }
            #endregion
            //Lambda声明属性
        public int id => 3;
        public void ShowLambda() => Console.WriteLine("LambdaFunc");

        //Linq To Sql(Queryable):SQL+ADO.NET
        //Where:完成对数据库的过滤,封装通用代码。

        //Linq To XML

        //Linq To Excel/Nosql

        //Linq To Everything
    }

        #endregion

    /// <summary>
    /// 学生类
    /// </summary>
    public class Student
    {
        public int Id { get; set; }
        public int ClassId { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

        public void Study()
        {
            Console.WriteLine("自学C#高级课程");
        }
        public void StudyHard()
        {
            Console.WriteLine("努力自学C#高级课程");
        }
    }

    /// <summary>
    /// 班级类
    /// </summary>
    public class Class
    {
        public int Id;
        public string ClassName;
    }

    /// <summary>
    /// 扩展方法:静态类里面的静态方法,第一个参数类型前面加上this
    /// 用途:不修改类,增加方法,用起来方便一些。
    /// 缺陷:如果类内已经有了扩展方法相同的方法,优先调用类内的实例方法(有隐患)。
    /// 指定类型扩展,不要扩展object。
    /// </summary>
    public static class ExtendMethod
    {
        public static void Sing(this Student student)
        {
            Console.WriteLine("Sing a song");
        }

        /// <summary>
        /// null默认是defaultValue,默认是0
        /// </summary>
        /// <param name="iValue"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int ToInt(this int? iValue, int defaultValue = 0)
        {
            return iValue ?? defaultValue;//如果iValue不为空,返回iValue,否则返回-1。
        }

        /// <summary>
        /// 扩展基类型,导致任何子类都有这个方法,而且可能覆盖方法名相同的方法,非常不推荐扩展object类型
        /// </summary>
        /// <param name="oValue"></param>
        /// <returns></returns>
        public static int Length(this object oValue)
        {
            return oValue == null ? 0 : oValue.ToString().Length;
        }

        /// <summary>
        /// 泛型扩展方法要加约束,否则和扩展object类型效果一样
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public static void ExtendShow<T>(this T t) where T : Student  //泛型约束
        {
            Console.WriteLine("I am ExtendShow");
        }

        /// <summary>
        /// 扩展方法,只针对Student
        /// </summary>
        /// <param name="source"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static List<Student> CgcWhere(this List<Student> source, Func<Student, bool> func)
        {
            var list = new List<Student>();
            foreach (var item in source)
            {
                if (func.Invoke(item))
                {
                    list.Add(item);
                }
            }
            return list;
        }

        /// <summary>
        /// 泛型扩展方法,可以针对任何类型
        /// </summary>
        /// <param name="source"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static List<T> GenericCgcWhere<T>(this List<T> source, Func<T, bool> func)
        {
            var list = new List<T>();
            foreach (var item in source)
            {
                if (func.Invoke(item))
                {
                    list.Add(item);
                }
            }
            return list;
        }

        /// <summary>
        /// 加上迭代器的扩展方法,按需加载:标准的Linq
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IEnumerable<T> YieldCgcWhere<T>(this IEnumerable<T> source, Func<T, bool> func)
        {
            if(source==null)
            {
                throw new Exception("source is null");
            }
            if(func==null)
            {
                throw new Exception("func is null");
            }
            foreach (var item in source)
            {
                if (func.Invoke(item))
                {
                    yield return item;
                }
            }
        }
    }
        #endregion
}

相关标签: c# lambda