Csharp學習Linq

Linq的學習

這裏繼續使用之前文章創建的學生類,首先簡單介紹一下linq的使用。

Student.cs

 public class Student
 {
     public int Id { get; set; }
     public int ClassId { get; set; }

     public string Name { get; set; }

     public int Age { get; set; }

     public string Description { get; set; }

     public void Study()
     {
         Console.WriteLine($"{this.Id} {this.Name} 跟着老師學習 .Net開發");

     }

     public void StudyQt()
     {
         Console.WriteLine($"{this.Id} {this.Name} 跟着老師學習C++ Qt");
     }
 }

初始化學生數據

public class LinqPrinciple
{
    private List<Student> GetStudentsList()
    {
        List<Student> students = new List<Student>()
        { new Student() { Id = 1, ClassId = 1, Name = "張三", Age = 20, Description = "張三是一個好學生" },
             new Student() { Id = 2, ClassId = 1, Name = "李四", Age = 21, Description = "李四是一個好學生" },
             new Student() { Id = 3, ClassId = 2, Name = "王五", Age = 22, Description = "王五是一個好學生" },
             new Student() { Id = 4, ClassId = 2, Name = "趙六", Age = 23, Description = "趙六是一個好學生" },
             new Student() { Id = 5, ClassId = 3, Name = "孫七", Age = 24, Description = "孫七是一個好學生" },
             new Student() { Id = 6, ClassId = 3, Name = "周八", Age = 25, Description = "周八是一個好學生" },
              new Student() { Id = 7, ClassId = 1, Name = "綠春", Age = 30, Description = "張三是一個好學生" },
             new Student() { Id = 8, ClassId = 1, Name = "麻醉", Age = 35, Description = "李四是一個好學生" },
             new Student() { Id = 9, ClassId = 2, Name = "開天", Age = 26, Description = "王五是一個好學生" },
             new Student() { Id = 10, ClassId = 2, Name = "匹敵", Age = 22, Description = "趙六是一個好學生" },
             new Student() { Id = 11, ClassId = 3, Name = "獨輪車", Age = 23, Description = "孫七是一個好學生" },
             new Student() { Id = 12, ClassId = 3, Name = "火箭英", Age = 20, Description = "周八是一個好學生" }

        };
        return students;
    }
}

下面寫幾個簡單的linq的語句,大概知道一下它的使用.


   public void  Show()
   {
       //獲取一下ClassID爲3的學生們
       List<Student> students = GetStudentsList();
       List<Student> studentsId=students.Where(s => s.ClassId == 3).ToList();
       Console.WriteLine("********************************1*****************************");
       foreach (var student in studentsId)
       {
           Console.WriteLine($"{student.Id} {student.Name} {student.Age} {student.Description}");
       }
       Console.WriteLine("********************************2*****************************");
       //獲取一下年紀大於24的學生們
       List<Student> studentsAge = students.Where(s => s.Age > 24).ToList();
       foreach (var student in studentsAge)
       {
           Console.WriteLine($"{student.Id} {student.Name} {student.Age} {student.Description}");
       }
       Console.WriteLine("********************************3*****************************");
       //獲取一下年紀小於23同時ClassID爲2的學生們
       List<Student> studentsAgeClassId = students.Where(s => s.Age < 23 && s.ClassId == 2).ToList();
       foreach (var student in studentsAgeClassId)
       {
           Console.WriteLine($"{student.Id} {student.Name} {student.Age} {student.Description}");
       }
   }

linq的原理的探究

下面嘗試探索一下這個linq的本質是什麼?

嘗試自己實現一下這3個需求代碼,如下

 List<Student> students = GetStudentsList();
 List<Student> studentsId=new List<Student>();
 foreach (var student in students)
 {
     if (student.ClassId == 3)
     {
         studentsId.Add(student);
     }
 }

 List<Student> studentsAge=new List<Student>();
 foreach (var student in students)
 {
     if (student.Age > 24)
     {
         studentsAge.Add(student);
     }
 }

 List<Student> studentsAgeClassId=new List<Student>();
 foreach (var student in students)
 {
     if (student.Age < 23 && student.ClassId == 2)
     {
         studentsAgeClassId.Add(student);
     }
 }

這上面的代碼有什麼問題?

大量的重複代碼---最好是封裝一些,把重複的代碼統一封裝;

這裏使用一個解決方案

封裝一個方法,將判斷的邏輯獨立到一個小方法中去.

        public static bool  IsOk01(Student student)
        {
            return student.ClassId == 3;
        }

        public static bool IsOk02(Student student)
        {
            return student.Age > 24;
        }

        public static bool IsOk03(Student student)
        {
            return student.Age < 23 && student.ClassId == 2;
        }
        public static List<Student> DragonWhere(List<Student> studentlist,Func<Student,bool> Func)
        {
            List<Student> students = new List<Student>();
            foreach (var student in studentlist)
            {
                if (Func(student))
                {
                    students.Add(student);
                }
            }
            return students;
        }

嘗試使用一下封裝的函數

List<Student> students = GetStudentsList();
List<Student> studentId= MethodExtension.DragonWhere(students, MethodExtension.IsOk01);

這裏還可以使用擴展方法和lambda表達式進一步的優化我們的代碼

      public static List<Student> DragonWhere(this List<Student> studentlist,Func<Student,bool> Func)
        {
            List<Student> students = new List<Student>();
            foreach (var student in studentlist)
            {
                if (Func(student))
                {
                    students.Add(student);
                }
            }
            return students;
        }

在調用的時候,

List<Student> students = GetStudentsList();
List<Student> studentsId = students.DragonWhere(s => s.ClassId == 3);

這裏就串聯上了我們之前學到的知識,最後爲了支持多種數據類型,使用上泛型,最後我們就得到了最終封裝的方法.

 public static List<T> DragonWhere<T>(this List<T> studentlist,Func<T,bool> Func)
 {
     List<T> students = new List<T>();
     foreach (var student in studentlist)
     {
         if (Func(student))
         {
             students.Add(student);
         }
     }
     return students;
 }

這裏也要使用ilspy反編譯一下它們的實現是如何?

看起來跟我們自己實現的Where差不多的樣子.
img

再去看一下它的movenext函數.

img

這個就是一個yield return反彙編出來的狀態機的代碼。

linq常見的語句

 public void Show()
 {
     List<Student> studentList = this.GetStudentList(); 
     #region Linq 擴展方法&表達式
     {  
         var list = studentList.Where<Student>(s => s.Age < 30); //list裏面必然是符合要求的數據;
         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;   //list裏面必然是符合要求的數據;

         foreach (var item in list)
         {
             Console.WriteLine("Name={0}  Age={1}", item.Name, item.Age);
         }
     }
     #endregion

     #region linq to object Show
     {
         Console.WriteLine("********************");
         var list = studentList.Where<Student>(s => s.Age < 30)
                              .Select(s => new  //投影:可以做一些自由組裝+ new 一個匿名類,也可以new 具體類;
                              {
                                  IdName = s.Id + s.Name,
                                  ClassName = s.ClassId == 2 ? "高級班" : "其他班"
                              });
         foreach (var item in list)
         {
             Console.WriteLine("Name={0}  Age={1}", item.ClassName, item.IdName);
         }
     }
     {
         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("Name={0}  Age={1}", item.ClassName, item.IdName);
         }
     }
     {
         Console.WriteLine("********************");
         var list = studentList.Where<Student>(s => s.Age < 30)//條件過濾
                              .Select(s => new//投影
                              {
                                  Id = s.Id,
                                  ClassId = s.ClassId,
                                  IdName = s.Id + s.Name,
                                  ClassName = s.ClassId == 2 ? "高級班" : "其他班"
                              })
                              .OrderBy(s => s.Id)//排序 升序
                              .ThenBy(s => s.ClassName) //多重排序,可以多個字段排序都生效
                              .OrderByDescending(s => s.ClassId)//倒排
                              .Skip(2)//跳過幾條  //必須要先排序
                              .Take(3)//獲取幾條 //必須要先排序
                              ;
         foreach (var item in list)
         {
             Console.WriteLine($"Name={item.ClassName}  Age={item.IdName}");
         }
     }
     {//group by·
         Console.WriteLine("********************");
         var list = from s in studentList
                    where s.Age < 30
                    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}  maxAge={item.maxAge}");
         }
         //group by new {s.ClassId,s.Age}
         //group by new {A=s.ClassId>1}
     }
     {
         Console.WriteLine("********************");
         var list = studentList.GroupBy(s => s.ClassId).Select(sg => new
         {
             key = sg.Key,
             maxAge = sg.Max(t => t.Age)
         });
         foreach (var item in list)
         {
             Console.WriteLine($"key={item.key}  maxAge={item.maxAge}");
         }
     }
     {
         var list = studentList.GroupBy(s => s.ClassId);
         foreach (var date in list) ///實現了IEnumerable
         {
             Console.WriteLine(date.Key);

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

         }

     }
     List<Class> classList = new List<Class>()
         {
             new Class()
             {
                 Id=1,
                 ClassName="架構班"
             },
             new Class()
             {
                 Id=2,
                 ClassName="高級班"
             },
             new Class()
             {
                 Id=3,
                 ClassName="全棧班"
             },
         };
     {

         //Join 
         var list = from s in studentList
                    join c in classList on s.ClassId equals c.Id  //只能使用equals  不能使==
                    select new
                    {
                        Name = s.Name,
                        CalssName = c.ClassName
                    };
         foreach (var item in list)
         {
             Console.WriteLine($"Name={item.Name},CalssName={item.CalssName}");
         }
     }
     {
         var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
         {
             Name = s.Name,
             CalssName = c.ClassName
         });
         foreach (var item in list)
         {
             Console.WriteLine($"Name={item.Name},CalssName={item.CalssName}");
         }
     }
     {//左連接
         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,
                        CalssName = sc == null ? "無班級" : sc.ClassName//c變sc,爲空則用
                    };
         foreach (var item in list)
         {
             Console.WriteLine($"Name={item.Name},CalssName={item.CalssName}");
         }
         Console.WriteLine(list.Count());
     }
     {
         var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
         {
             Name = s.Name,
             CalssName = c.ClassName
         }).DefaultIfEmpty();//爲空就沒有了
         foreach (var item in list)
         {
             Console.WriteLine($"Name={item.Name},CalssName={item.CalssName}");
         }
         Console.WriteLine(list.Count());
     }
     {

         //左連接和右鏈接  就是鏈接對象交換一下即可;

     }
     #endregion
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章