日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

C# 委托 (一)—— 委托、 泛型委托与Lambda表达式

發布時間:2025/3/15 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# 委托 (一)—— 委托、 泛型委托与Lambda表达式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C# 委托 (一)—— 委托、 泛型委托與Lambda表達式

2018年08月19日 20:46:47 wnvalentin 閱讀數 2992 版權聲明:此文乃博主之原創。鄙人才疏,望大俠斧正。此文可轉載,然需明根以溯源。 https://blog.csdn.net/wnvalentin/article/details/81840339

目錄

1 委托的含義

2 委托聲明、實例化和調用

2.1 委托的聲明

2.2 委托的實例化

2.3 委托實例的調用

3 泛型委托

3.1 Func委托

3.2 Action委托

3.3 Predicate委托

4 匿名委托

5 Lambda表達式

5.1 表達式Lambda

5.2 語句Lambda


1 委托的含義

當需要將一個方法當作另一個方法的參數時,對于某些語言例如C/C++等,需要用函數指針來處理。而對于C#來說,則使用委托機制。

例如,當我們需要對一個泛型集合ICollection<T>進行排序時,我們定義一個Sort方法,那么這個方法需要哪些參數才能進行排序呢?首先,肯定需要一個Collection<T>對象作為輸入參數,代表要排序的對象集合;然后,Sort方法還需要知道如何比較兩個對象,經過比較之后才能決定讓哪個對象排在前面。因此,Sort方法需要第二個參數,這個參數是一個方法,代表著比較排序對象的方法。這時候這個比較方法參數就只能是一個委托。我們在調用Sort方法對具體的類進行排序時,通過委托傳入一個具體類的比較方法。

再比如,在使用LINQ時,我們經常會用到Where()、Find()等擴展方法,實現對集合中元素的篩選或查找。Where()方法擁有一個Func<T>參數,它就是一個委托。我們調用Where()時需要給這個委托傳遞一個方法,告訴Where篩選器篩選元素的規則方法。

委托是一種特殊的類,是一種能夠引用方法的類。在創建委托時,就是創建了一個存儲方法引用的對象。

委托是類型安全的。C函數指針只是一個指向一個存儲單元的指針,不能保證指向的內容就是正確類型的函數。而對于C#的委托而言,聲明一個委托時必須指定返回類型和參數,.NET編譯器會嚴格檢查方法的參數和返回類型和委托是否匹配,檢查通過后才能進行轉換。轉換之后的委托實例作為一個參數,傳遞給調用它的函數。

一個委托可以被傳遞任何符合要求的方法。不同場合需要不同方法時,在調用的地方直接將委托參數替換為實際方法就行。因此,委托調用的方法是在程序運行時才能確定的。

2 委托聲明、實例化和調用

2.1 委托的聲明

前面提到過,委托是一種特殊的類,因此委托的聲明與類的聲明方法類似,在任何可以聲明類的地方都可以聲明委托。委托聲明用delegate關鍵字,同時委托要指明方法參數和返回值,寫法與方法類似。綜合類的聲明和方法的聲明,委托聲明寫成如下形式:

[訪問修飾符] delegate 返回值類型 委托名 (形參列表);

委托的聲明實際上是定義了一個派生于System.Delegate類的類,這與一般類的聲明語法不同。編譯器會根據委托的聲明自動創建一個委托的類并實現細節。

接下來我們以一個簡單的List<Student>排序為例進行說明。假設我們有一個Student類,存放學生信息,擁有姓名、年齡和學號三個屬性:

public class Student {public string Name { get; set; } public int Age { get; set; } public int Num { get; set; } }

然后創建一個List<Student>:

Student s1 = new Student() { Name = "小紅", Age = 10, Num = 1001 }; Student s2 = new Student() { Name = "小華", Age = 9, Num = 1002 }; List<Student> sList = new List<Student>(); sList.Add(s1); List.Add(s2);

我們的目標是想給List<Student>對象添加一個排序方法,這個排序方法可以根據年齡或者學號來排序,具體需要哪一種排序需要在客戶端調用時指定。(簡單起見,本案例中List<Student>只包含兩個元素,不糾結于排序算法)

按照要求,Student對象的比較有兩種方法,我們實現兩個比較方法,供委托使用:

//比較年齡 public static bool Younger(Student s1, Student s2) => s1.Age <= s2.Age; //比較學號 public static bool NumSmaller(Student s1, Student s2) => s1.Num <= s2.Num;

由上,我們可以抽象出一個代表比較Student的方法的委托:

public delegate bool CompareDelegate(Student first, Student second);

這個委托的類名為CompareDelegate,注意到委托聲明的返回值類型、參數與其代表的方法要完全一致。

2.2 委托的實例化

與普通類的使用方法相同,聲明了委托之后,我們必須給委托傳遞一個具體的方法,才能在運行時調用委托實例。委托實例包含了被傳遞給它的方法的信息,在運行時,調用委托實例就相當于執行它當中的方法。

委托實例化格式如下:

委托類名 委托實例名 = new 委托類名(Target)?;

其中,委托實例名是自定義的名稱,Target是要傳入的方法的名稱。注意,Target是方法的引用,不能帶()。帶()的話是該方法的調用。區分引用和調用。

委托的實例化還有一種簡單的方法:

委托類名 委托實例名 = Target;

在需要委托實例的地方直接傳入Target引用即可,C#編譯器會自動根據委托類型進行驗證,這稱為“委托推斷”。

案例:

//以下兩種方法等價 CompareDelegate myCompareDelegate = new CompareDelegate(Younger); CompareDelegate myCompareDelegate = Younger;//委托推斷

2.3 委托實例的調用

委托實例等價于它當中實際方法,因此可以使用反射的Invoke()方法調用委托實例,也可以直接在委托實例后加上()進行調用。

我們下面看一下委托所代表的方法是如何被業務方法調用的。這里我們的業務是排序SortStudent方法:

//使用委托的業務方法 public static void SortStudent(List<Student> sList, CompareDelegate CompareMethod) { if (CompareMethod(sList[0], sList[1]))//等價于CompareMethod.Invoke(sList[0], List[1]) { //sList[0]已經在sList[1]前面了,所以什么也不用做 } else { sList.Reverse();//交換位置 } //獲取排名采用的比較方法的名稱 Console.WriteLine($"\r\n按照 {CompareMethod.Method.Name} 排名:"); //打印排序后的鏈表 foreach (Student s in sList) Console.WriteLine($"{s.Name} {s.Age} {s.Num} "); }

這里Sort方法擁有一個CompareDelegate類型的委托實例CompareMethod,它可直接當做具體方法進行調用。

在客戶端對委托進行實例化后,調用SortStudent()方法就可以進行排序了。

//委托的實例化與使用 CompareDelegate myCompareDelegate = NumSmaller;//采用比較學號的方法 SortStudent(sList, myCompareDelegate);//使用委托推斷,與上兩行等價 SortStudent(sList, NumSmaller);

輸出如下:

按照 NumSmaller 排名: 小紅 10 1001 小華 9 1002

3 泛型委托

我們每次要使用一個委托時,都需要先聲明這個委托類,規定參數和返回值類型,然后才能實例化、調用。為了簡化這個過程,?.NET 框架為我們封裝了三個泛型委托類,因此大部分情況下我們不必再聲明委托,可以拿來直接實例化使用,方便了我們的日常Coding。

.這三種泛型委托包括:Func<T>委托、Action<T>委托和Predicate<T>委托。

3.1 Func<T>委托

Func<T>委托代表著擁有返回值的泛型委托。Func<T>有一系列的重載,形式如 Func<T1,T2, ... TResult>,其中TResult代表委托的返回值類型,其余均是參數類型。只有一個T時,即Func<TResult>,代表該委托是無參數的。.NET封裝了最多16個輸入參數的Funct<>委托。

需要特別注意的是,若方法返回 void ,由于 void 不是數據類型,因此不能定義Func<void>委托。返回 void 的泛型委托見下文的Action<T>。

Func<T>的使用方法與一般的委托相同。例如上面的案例可改寫如下;

public static void SortStudent(List<Student> sList,Func<Student,Student,bool> CompareMethod) { if(CompareMethod(sList[0], sList[1])) { } else { sList.Reverse(); } Console.WriteLine($"\r\n按照 {CompareMethod.Method.Name} 排名:"); foreach (Student s in sList) Console.WriteLine($"{s.Name} {s.Age} {s.Num} "); } //客戶端調用 Func<Student, Student, bool> myCompareFunc = NumSmaller; SortStudent2(sList, myCompareFunc);

注意SortStudent2方法的委托參數也必須是Func<Student, Student, bool>,才能滿足方法調用時類型一致的要求。?

3.2 Action<T>委托

Action<T>委托代表返回值為空 void 的委托,它也有一些列重載,最多擁有16個輸入參數。用法與Func<T>相同。

3.3 Predicate<T>委托

這個一般用的較少,它封裝返回值為bool類型的委托,可被Func<T>代替。

4 匿名委托

采用匿名方法實例化的委托稱為匿名委托。

每次實例化一個委托時,都需要事先定義一個委托所要調用的方法。為了簡化這個流程,C# 2.0開始提供匿名方法來實例化委托。這樣,我們在實例化委托時就可以 “隨用隨寫” 它的實例方法。

使用的格式是:

委托類名 委托實例名 = delegate (args) {方法體代碼} ;

這樣就可以直接把方法寫在實例化代碼中,不必在另一個地方定義方法。當然,匿名委托不適合需要采用多個方法的委托的定義。

使用匿名方法,以上代碼可改寫為:

CompareDelegate anonymousCompare = delegate (Student s3, Student s4) { return s1.Num <= s2.Num; }; SortStudent(sList, anonymousCompare);

需要說明的是,匿名方法并不是真的“沒有名字”的,而是編譯器為我們自動取一個名字。SortStudent方法打印了委托調用的方法的名字(見上文代碼),我們可以看到如下輸出:

按照 <Main>b__0 排名: 小紅 10 1001 小華 9 1002

?編譯器為我們的匿名方法取了一個b__0的名字。

5 Lambda表達式

江山代有才人出,縱然匿名方法使用很方便,可惜她很快就成了過氣網紅,沒能領多長時間的風騷。如今已經很少見到了,因為delegate關鍵字限制了她用途的擴展。自從C# 3.0開始,她就被Lambda表達式取代,而且Lambda表達式用起來更簡單。Lambda表達式本質上是改進的匿名方法。

Lambda表達式的靈感可能是來源于數學中的函數表達式,例如下圖:

Lambda表達式把其中的箭頭用 => 符號表示。

如今Lambda表達式已經應用在很多地方了,例如方法體表達式(Expression-Bodied Methods)、自動只讀屬性表達式等等。

Lambda表達式形式上分為兩種:

5.1 表達式Lambda

當匿名函數只有一行代碼時,可采用這種形式。例如:

CompareDelegate LambdaCompare = (s4, s5) => s4.Age <= s5.Age;

其中=>符號代表Lambda表達式,它的左側是參數,右側是要返回或執行的語句。參數要放在圓括號中,若只有一個參數,為了方便起見可省略圓括號。有多個參數或者沒有參數時,不可省略圓括號。

相比匿名函數,在表達式Lambda中,方法體的花括號{}和return關鍵字被省略掉了。

其實,上文定義NumSmaller()和Younger()方法時,由于這兩個方法主體只有一行代碼,所以用的也是表達式Lambda,這是Lambda表達式的推廣,?是C# 6 編譯器提供的一個語法糖。

5.2 語句Lambda

當匿名函數有多行代碼時,只能采用語句Lambda。例如,上面的表達式Lambda可改寫為語句Lambda:

CompareDelegate LambdaCompare = (s4, s5) => {return s4.Age <= s5.Age; };

語句Lambda不可以省略{}和return語句。

轉載于:https://www.cnblogs.com/Siny0/p/11155838.html

總結

以上是生活随笔為你收集整理的C# 委托 (一)—— 委托、 泛型委托与Lambda表达式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。