C# 基礎知識系列-7 Linq詳解

来源:https://www.cnblogs.com/c7jie/archive/2020/04/04/12632800.html
-Advertisement-
Play Games

前言 在上一篇中簡單介紹了Linq的入門級用法,這一篇嘗試講解一些更加深入的使用方法,與前一篇的結構不一樣的地方是,這一篇我會先介紹Linq里的支持方法,然後以實際需求為引導,分別以方法鏈的形式和類SQL的形式寫出來。 前置概念介紹 1. 謂詞、斷言,等價於 即返回bool的表達式 2. 表達式樹, ...


前言

在上一篇中簡單介紹了Linq的入門級用法,這一篇嘗試講解一些更加深入的使用方法,與前一篇的結構不一樣的地方是,這一篇我會先介紹Linq里的支持方法,然後以實際需求為引導,分別以方法鏈的形式和類SQL的形式寫出來。

前置概念介紹

  1. Predicate<T> 謂詞、斷言,等價於 Func<T,bool> 即返回bool的表達式
  2. Expression<TDelegate> 表達式樹,這個類很關鍵,但是在這裡會細說,我們會講它的一個特殊的泛型類型:Expression<Func<T,bool>> 這個在某些數據源的查詢中十分重要,它代表lambda表達式中一種特殊的表達式,即沒有大括弧和return關鍵字的那種。

我們先準備兩個類

  1. Student/學生類:
/// <summary>
/// 學生
/// </summary>
public class Student
{
    /// <summary>
    /// 學號
    /// </summary>
    public int StudentId { get; set; }
    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// 班級
    /// </summary>
    public string Class { get; set; }
    /// <summary>
    /// 年齡
    /// </summary>
    public int Age { get; set; }
}
  1. Subject/科目類:

    /// <summary>
    /// 科目
    /// </summary>
    public class Subject
    {
        /// <summary>
        /// 名稱
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 年級
        /// </summary>
        public string Grade { get; set; }
        /// <summary>
        /// 學號
        /// </summary>
        public int StudentId { get; set; }
        /// <summary>
        /// 成績
        /// </summary>
        public int Score { get; set; }
    }
    

Subject 和Student通過學號欄位一一關聯,實際工作中數據表有可能會設計成這。

那麼先虛擬兩個數據源:IEnumerable<Student> studentsIEnumerable<Subject> subjects。先忽略這兩個數據源的實際來源,因為在開發過程中數據來源有很多種情況,有資料庫查詢出來的結果、遠程介面返回的結果、文件讀取的結果等等。不過最後都會整理成IEnumerable<T>的子介面或實現類的對象。

常見方法介紹

Where 過濾數據,查詢出符合條件的結果

where的方法聲明:

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

可以看出不會轉換數據類型,通過給定的lambda表達式或者一個方法進行過濾,獲取返回true的元素。

示例:

// 獲取年紀大於10但不大於12的同學們
List<Student> results = students.Where(t=>t.Age >10 && t.Age<= 12).ToList();

註意在調用ToList之後數據才會實質上查詢出來。

Group 分組,依照指定內容進行分組

Group的方法聲明有很多種:

最常用的一種是:

public static IEnumerable<System.Linq.IGrouping<TKey,TSource>> GroupBy<TSource,TKey> (this IEnumerable<TSource> source, Func<TSource,TKey> keySelector);

示例:

//將學生按照班級進行分組
List<IGrouping<string,Student>> list = students.GroupBy(p => p.Class).ToList();

OrderBy/OrderByDescending 進行排序,按條件升序/降序

它們是一對方法,一個是升序一個降序,其聲明是一樣的:

常用的是:

public static System.Linq.IOrderedEnumerable<TSource> OrderBy<TSource,TKey> (this IEnumerable<TSource> source, Func<TSource,TKey> keySelector);

示例:

//按年齡的升序排列:
List<Student> results = students.OrderBy(p => p.Age).ToList();
//按年齡的降序排列:
List<Student> results = students.OrderByDescending(p => p.Age).ToList();

First/Last 獲取數據源的第一個/最後一個

這組方法有兩個常用的重載聲明:

First:

// 直接獲取第一個
public static TSource First<TSource> (this IEnumerable<TSource> source);
// 獲取滿足條件的第一個
public static TSource First<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);

Last:

// 直接獲取最後一個
public static TSource Last<TSource> (this IEnumerable<TSource> source);
// 獲取最後一個滿足條件的元素
public static TSource Last<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);

示例:

Student student = students.First();// 等價於 students[0];
Student student = students.First(p=>p.Class == "一班");//獲取數據源中第一個一班的同學

Student student = students.Last();//最後一個學生
Student student = students.Last(p=>p.Class == "三班");//獲取數據源中最後一個三班的同學

註意:

  • 在某些數據源中使用Last會報錯,因為對於一些管道類型的數據源或者說非同步數據源,程式無法確認最後一個元素的位置,所以會報錯。解決方案:先使用OrderBy對數據源進行一次排序,使結果與原有順序相反,然後使用First獲取
  • 當數據源為空,或者不存在滿足條件的元素時,調用這組方法會報錯。解決方案:調用FirstOrDefault/LastOrDefault,這兩組方法在無法查詢到結果時會返回一個預設值。

Any/All 是否存在/是否都滿足

Any:是否存在元素滿足條件

有兩個版本,不過意思可能不太一樣:

public static bool Any<TSource> (this IEnumerable<TSource> source);//數據源中是否有數據
//================
//是否存在滿足條件的數據
public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);

All :是否都滿足條件:

public static bool Any<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);

示例:

// 是否有學生
bool isAny =  students.Any();
// 是否有五班的同學
bool isFive = students.Any(p=>p.Class == "五班");
// 是否所有學生的年紀都不小於9歲
bool isAll = students.All(p=>p.Age >= 9);

Skip 略過幾個元素

Skip一共有三個衍生方法:

第一個:Skip 自己: 略過幾個元素,返回剩下的元素內容

public static IEnumerable<TSource> Skip<TSource> (this IEnumerable<TSource> source, int count);

第二個:SkipLast,從尾巴開始略過幾個元素,返回剩下的元素內容

public static IEnumerable<TSource> SkipLast<TSource> (this IEnumerable<TSource> source, int count);

第三個:SkipWhile,跳過滿足條件的元素,返回剩下的元素

public static IEnumerable<TSource> SkipWhile<TSource> (this IEnumerable<TSource> source, Func<TSource,bool> predicate);

示例:

// 不保留前10個學生
List<Student> results = students.Skip(10).ToList();
// 不保留後10個學生
List<Student> results = students.SkipLast(10).ToList();
// 只要非一班的學生
List<Student> results = students.SkipWhere(p=>p.Class=="一班").ToList();
//上一行代碼 等價於 = students.Where(p=>p.Class != "一班").ToList();

Take 選取幾個元素

Take與Skip一樣也有三個衍生方法,聲明的參數類型也一樣,這裡就不對聲明做介紹了,直接上示例。

//選取前10名同學
List<Student> results = students.Take(10).ToList();
// 選取最後10名同學
List<Student> results = students.TakeLast(10).ToList();
//選取 一班的學生
List<Student> results = students.TakeWhile(p=>p.Class=="一班").ToList();
// 上一行 等價於 = students.Where(p=>p.Class=="一班").ToList();

在使用Linq寫分頁的時候,就是聯合使用Take和Skip這兩個方法:

int pageSize = 10;//每頁10條數據
int pageIndex = 1;//當前第一頁
List<Student> results = students.Skip((pageIndex-1)*pageSize).Take(pageSize).ToList();

其中 pageIndex可以是任意大於0 的數字。Take和Skip比較有意思的地方就是,如果傳入的數字比數據源的數據量大,根本不會爆粗,只會返回一個空數據源列表。

Select 選取

官方對於Select的解釋是,將序列中的每個元素投影到新的表單里。我的理解就是,自己 定義一個數據源單個對象的轉換器,然後按照自己的方式對數據進行處理,選擇出一部分欄位,轉換一部分欄位。

所以按我的理解,我沒找到java8的同效果方法。(實際上java用的是map,所以沒找到,

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • #include<stdio.h> int main(void) { int a; scanf("%d",&a); switch(a) { case 1: printf("a"); case 2: printf("b"); case 3: printf("c\n"); } return 0; } d ...
  • #include<stdio.h> int main(void) { int a,b,c,d; printf("請輸入三個整數"); scanf("%d%d%d",&a,&b,&c); if (c>b) { d=b; b=c; c=d; } if (b>a) { d=a; a=b; b=d; } i ...
  • 1. 2.創建頭文件選擇C/C++ Header file 3.源程式文件與頭文件不在一個地址話,需要在導入的時候寫清楚頭文件所在地址 例如名為giligli.h的頭文件 #include”地址giligli.h” 4. 如圖D包含了兩個a 重覆定義會產生錯誤。利用條件編譯可以很好的避免重覆定義 # ...
  • 前言:在大一學習了C語言之後,基本掌握了一門面向過程的程式設計語言,本學期所學習的java是一門面向對象的語言,在問題的解決方面不像C一樣是以過程來思考問題,而是要以面向對象的思維來解決問題。此篇文章是對於本學期前三次Java作業的一個階段性總結,第一次作業花費了最多的時間,有一個測試點沒有過,第二 ...
  • 為表達全國各族人民對抗擊新冠肺炎疫情鬥爭犧牲烈士和逝世同胞的深切哀悼,國務院今天發佈公告,決定2020年4月4日舉行全國性哀悼活動。 當使用控制項模板時,需要決定如何更廣泛地共用模板,以及是否希望自動地或明確地位用模板。 第一個問題是關於希望在何處使用模板的問題。例如,是將它們限制在特定視窗中嗎?大多 ...
  • 2020年4月2日微軟.NET 團隊的項目經理 Richard 在博客上 發佈了.NET 5 Preview 2:https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-2/ ,3月16號,Scott Hunter 在博客中發 ...
  • 前言 命名空間已經在 .NET 中使用了多年,一直追溯到 .NET Framework 1.1。它在 .NET 實施本身的數百個位置中使用,並且直接被成千上萬個應用程式使用。在所有這些方面,它也是 CPU 消耗的重要來源。 但是,從性能角度來看,正則表達式在這幾年間並沒有獲得太多關註。在 2006 ...
  • 在這篇文章中,我將詳細講解ASP.NET Core Project File.如果你還沒看我這個系列的前面幾篇文章,先去看看,打好基礎,再來看這篇吧。 如果你使用過之前版本的.NET Framework,你就會知道,當你使用C#創建應用程式的時候,.NET Framework框架將會創建尾碼名為”. ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...