C# 委托知識總結

来源:https://www.cnblogs.com/caiyt/archive/2018/06/01/9120735.html
-Advertisement-
Play Games

原文地址:http://www.cnblogs.com/qingyuan/archive/2010/05/11/1732415.html 1.什麼是委托,為什麼要使用委托 我正在埋頭苦寫程式,突然想喝水,但是又不想自己去掉杯水而打斷自己的思路,於是我就想讓女朋友去給我倒水。她去給我倒水,首先我得讓她 ...


原文地址:http://www.cnblogs.com/qingyuan/archive/2010/05/11/1732415.html

1.什麼是委托,為什麼要使用委托

我正在埋頭苦寫程式,突然想喝水,但是又不想自己去掉杯水而打斷自己的思路,於是我就想讓女朋友去給我倒水。她去給我倒水,首先我得讓她知道我想讓她乾什麼,通知她之後我可以繼續寫自己的程式,而倒水的工作就交給了她。這樣的過程就相當於一個委托。

在程式過程中,當程式正在處理某個事件的時候,我需要另外的程式代碼去輔助處理一些事情,於是委托另一個程式模塊去處理,而委托就可以達到這種目的,我可以利用委托通知另外的程式模塊,該去調用哪個函數方法。委托其實就起到了這樣一個作用,將函數簽名傳遞到了另一個函數中。或許這樣講還是有些模糊,看看後面的具體實例。

 

2.委托的定義

delegate int Add(int num1,int num2);

delegate void ConvertNum(string result);

上面是定義兩個委托的例子,其實很簡單。聲明一個委托使用delegate關鍵字,上面分別是定義的帶返回值的委托和不帶返回值的委托, 

兩個委托都有傳遞參數,當然也可以不傳遞參數。其實委托也是一個類,委托派生為System.MulticastDelegate,而System.MulticastDelegate

又繼承System.Delegate,如果你知道這個也就明白委托其實是一個特殊的類。

 1 public delegate string TeaDelegate(string spText);
 2 
 3     public class DelegateSource
 4     {
 5         public void TestDelegate()
 6         {
 7             Operator op = new Operator();
 8             TeaDelegate tea = new TeaDelegate(op.GetTea);
 9             Console.WriteLine("去給我倒杯水");
10             Console.WriteLine();
11             string result=tea("去給我倒杯水");
12             Thread.Sleep(5000);
13             Console.WriteLine(result);
14             Console.WriteLine();
15         }
16     }
17 
18     public class Operator
19     {
20         /// <summary>
21         /// 確定是否還有水
22         /// </summary>
23         private bool flag = true;
24 
25         public string GetTea(string spText)
26         {
27             if (spText == "去給我倒杯水")
28             {
29                 if (flag)
30                 {
31                     return "老公,茶來了";
32                 }
33                 else
34                 {
35                     return "老公,沒有水了";
36                 }
37             }
38             return "等待.......";
39         }
40     }
View Code

 

輸出結果

 

上面使用最普通的一種方式來定義了一個委托的使用,這個例子雖然很簡單,但是能夠很形象的描述委托的使用。

 

3.委托的三種形式

(1).推斷

 1 public delegate string TeaDelegate(string spText);
 2 
 3     public class DelegateSource
 4     {
 5         public void TestDelegate()
 6         {
 7             Operator op = new Operator();
 8             TeaDelegate tea = op.GetTea;
 9             Console.WriteLine("去給我倒杯水");
10             Console.WriteLine();
11             string result=tea("去給我倒杯水");
12             Thread.Sleep(5000);
13             Console.WriteLine(result);
14             Console.WriteLine();
15         }
16     }
17 
18     public class Operator
19     {
20         /// <summary>
21         /// 確定是否還有水
22         /// </summary>
23         private bool flag = true;
24 
25         public string GetTea(string spText)
26         {
27             if (spText == "去給我倒杯水")
28             {
29                 if (flag)
30                 {
31                     return "老公,茶來了";
32                 }
33                 else
34                 {
35                     return "老公,沒有水了";
36                 }
37             }
38             return "等待.......";
39         }
40     }
View Code

 

在委托定義的例子中我們看到委托的使用方法是在委托實例化的時候指定的[new DelegateName(FunctionName)],這裡可能表述不是太但是代碼應該看得白了。 而委托的推斷,並沒有new 委托這個步驟,而是直接將Function 指定給委托。

(2).匿名函數

 1  public delegate string TeaDelegate(string spText);
 2 
 3     public class DelegateSource
 4     {
 5         public void TestDelegate()
 6         {
 7             Operator op = new Operator();
 8             bool flag = true;
 9             TeaDelegate tea = delegate(string spText)
10             {
11                 if (spText == "去給我倒杯水")
12                 {
13                     if (flag)
14                     {
15                         return "老公,茶來了";
16                     }
17                     else
18                     {
19                         return "老公,沒有水了";
20                     }
21                 }
22                 return "等待.......";
23             };
24 
25             Console.WriteLine("去給我倒杯水");
26             Console.WriteLine();
27             string result=tea("去給我倒杯水");
28             Thread.Sleep(5000);
29             Console.WriteLine(result);
30             Console.WriteLine();
31         }
32     }
View Code

 

至於匿名委托,給人的感覺更為直接了,都不用顯示的指定方法名,因為根本沒有方法,而是指定的匿名方法。匿名方法在.NET 中提高了 

代碼的可讀性和優雅性。對於更多操作較少的方法直接寫為匿名函數,這樣會大大提高代碼的可讀性。這裡有兩個值得註意的地方: 第一,不能使用

跳轉語句跳轉到該匿名方法外,第二 不能使用ref,out修飾的參數

(3).多播委托

 1 public delegate string TeaDelegate(string spText);
 2 
 3     public class DelegateSource
 4     {
 5         public void TestDelegate()
 6         {
 7             Operator op = new Operator();
 8 
 9             TeaDelegate tea1 = op.GetTea;
10             TeaDelegate tea2 = op.Speak;
11             TeaDelegate tea = tea1 + tea2;
12 
13             Console.WriteLine("去給我倒杯水");
14             Console.WriteLine();
15             string result=tea("去給我倒杯水");
16             Thread.Sleep(5000);
17             Console.WriteLine(result);
18             Console.WriteLine();
19         }
20     }
21 
22     public class Operator
23     {
24         /// <summary>
25         /// 確定是否還有水
26         /// </summary>
27         private bool flag = true;
28 
29         public string GetTea(string spText)
30         {
31             if (spText == "去給我倒杯水")
32             {
33                 if (flag)
34                 {
35                     return "老公,茶來了";
36                 }
37                 else
38                 {
39                     return "老公,沒有水了";
40                 }
41             }
42             return "等待.......";
43         }
44 
45 
46         public string Speak(string spText)
47         {
48             Console.WriteLine("\n去把我的設計圖稿拿來");
49             return null;
50         }
51     }
View Code

 

  還是上面的那個實例,我不盡想讓女朋友去給我掉杯水,還讓她幫我將程式設計圖稿拿過來。這個時候做的就不是一件事了,而是多件。

程式中也有很多這種情況,於是我們需要多播委托,在一個委托上指定多個執行方法,這是在程式中可以行的。上面提到了,委托直接繼承於

System.MulticastDelegate,正是因為這個類可以實現多播委托。如果調用多播委托,就可以按順序連續調用多個方法。為此,委托的簽名就必須返回void;否則,就只能得到委托調用的最後一個方法的結果。所以在上面的這段代碼中是得不到結果的

 

4.事件

使用C#編程,無論是WinForm,WebForm 給人很難忘得就是它的控制項,而他們的控制項庫使用方式都是使用使用事件驅動模式,而事件驅動模式卻少不了委托。話不多說,看代碼能夠更清好的理解事件和委托之間的聯繫. 

 1 public delegate void MyDelegate(string name);
 2 
 3     public class EventSource
 4     {
 5         public event MyDelegate Event_Delegate;
 6 
 7         public void SetCustomer(string name)
 8         {
 9             Console.WriteLine("事件發生.....\n");
10             Console.WriteLine("hi! "+name);
11         }
12 
13         public void TestEvent()
14         {
15             EventSource source = new EventSource();
16             Console.WriteLine("訂閱事件.....\n");
17             source.Event_Delegate += new MyDelegate(source.SetCustomer);
18             Console.WriteLine("觸發事件.....\n");
19             source.Event_Delegate("hechen");
20             Console.WriteLine("..................");
21         }
22     }
View Code

 

上面的代碼中我們定義了一個委托,然後定義了一個類EventSource,這個類中聲明瞭一個事件。定義一個事件使用event 關鍵字,定義一

個event必須指定這個event傳遞消息的委托,在觸發事件之前必需訂閱事件,我們使用+= new 語法來訂閱一個事件,也就相當於實例化一個事件。

當我們觸發事件的時候,就會調用相應的方法去處理。

 

5. 泛型委托

委托是類型安全的引用,泛型委托就和我們常用的泛型類一樣,這個類在使用的時候才能確定類型.通過泛型委托,我們可以在委托傳遞參數

之後知道它的類型.在.NET中有一個很典型的泛型委托:

public delegate voie EventHandler<TEventArgs>(object sender,TEventArgs e) where TEventArgs:EventArgs.

這是一個非常有特色的泛型委托,可能我們用的比較少,但是作用是不能忽視的。 我們看看三個非常具有代表性的泛型委托.現在.NET4.0已經出來了,但是泛型委托.NET2.0就出來了,Linq 大家用的那叫一個甜,

為啥 函數式編程風格,匿名方法,Lamda表達式表達式使用是如此的魅力。但是大家仔細觀察過沒有,Linq 中的方法有幾個經常出現的參數:

Action<T>,Predicate<T>,Func<T, Result>

 Func<T, E>:封裝一個具有一個參數並返回 E 參數指定的類型值的方法,T 是這個委托封裝方法的參數類型,E是方法的返回值類型。當然Func<T, Result> 只是其中的一種情況,這個委托還有其他的幾種情況:Func<T> 這個是方法沒有參數,返回值類型是T;Func<T1,T2,Result> 這個方法有兩個參數,類型分別為T1,T2,返回值是Result,還有Func<T1,T2,T3,Result>,Func<T1,T2,T3,T4,Result> 這幾中情況,具體情況就不介紹了.我們還可以通過擴展類型,擴展為更多的參數.

 1  public void TestFunc()
 2         { 
 3             TEventSource eventSource=new TEventSource();
 4             Func<string, string> func = eventSource.GetTea;
 5             string result = func("");
 6             Console.WriteLine(result);
 7         }
 8 
 9         public string GetTea(string context)
10         {
11             if (context == "")
12             {
13                 return "茶來了";
14             }
15             else
16             {
17                 return "設計稿子來了";
18             }
19         }
View Code

 

Action<T>:封裝一個方法,該方法只採用一個參數並且不返回值,包括Action<T>,Action<T1,T2>,Action<T1,T2,T3>,Action<T1,T2,T3,T4> 這幾種情況,也可以通過擴展方法去擴展參數的個數 。

 1 public void TestAction()
 2         {
 3             TEventSource eventSource = new TEventSource();
 4             Action<string> action = eventSource.Speak;
 5             action("Action<T> 泛型委托");
 6         }
 7 
 8         public void Speak(string context)
 9         {
10             Console.WriteLine(context);
11         }
View Code

 

Predicate<T>:表示定義一組條件並確定指定對象是否符合這些條件的方法。該委托返回的是一個bool類型的值,如果比較滿足條件 

返回true,否則返回false.其實上面的Func 委托可以包含這個委托.不過這個委托和上面的兩個不一樣,它只有一種類型

 1 public void TestPredicate()
 2         {
 3             TEventSource eventSource = new TEventSource();
 4             Predicate<int> predicate = eventSource.IsRigth;
 5             Console.WriteLine(predicate(0));
 6         }
 7 
 8         public bool IsRigth(int value)
 9         {
10             if (value == 0)
11             {
12                 return true;
13             }
14             else
15             {
16                 return false;
17             }
18         }
View Code

 

6.非同步委托

投票技術: 委托其實相當於一個線程,使用投票技術是使用非同步委托的一種實現方式.Delegate類提供了方法BeginInvoke(),可以傳送委托類型定義的輸入參數,其返回類型為IAsyncResult。IAsyncResult的IsCompleted屬性可以判斷委托任務是否完成

 1  public delegate int DelegateVote(int data, int ms);
 2     /// <summary>
 3     /// 使用投票操作完成委托任務
 4     /// </summary>
 5     public class VoteDelegate
 6     {
 7         /// <summary>
 8         /// 休眠特定時間執行操作
 9         /// </summary>
10         /// <param name="data"></param>
11         /// <param name="ms"></param>
12         /// <returns></returns>
13         public static int TakeWork(int data, int ms)
14         {
15             Console.WriteLine("開始調用TakeWork方法");
16             Thread.Sleep(ms);
17             Console.WriteLine("結束調用TakeWork方法");
18             return data + 10;
19         }
20 
21         public void TestDelegate()
22         {
23             DelegateVote voteDel = TakeWork;
24             IAsyncResult result = voteDel.BeginInvoke(1,5000,null,null);
25             while (result.IsCompleted == false)
26             {
27                 Console.WriteLine("等待......");
28                 Thread.Sleep(500);
29             }
30             int value = voteDel.EndInvoke(result);
31             Console.WriteLine("委托調用結果:  "+value);
32         }
33     }
View Code

 

等待句柄:等待句柄是使用AsyncWaitHandle屬性訪問,返回一個WaitHandle類型的對象,它可以等待委托線程完成其任務。在這個參數中可以設置最大的等待時間。

 1  public delegate string WaitDelegate(string content);
 2 
 3     public class WaitHandlerDelegate
 4     {
 5         public void TestWaitHander()
 6         {
 7             WaitDelegate del = GetTea;
 8             IAsyncResult ar = del.BeginInvoke("hechen", null, null);
 9             while (true)
10             {
11                 Console.Write(".");
12                 if (ar.AsyncWaitHandle.WaitOne(50, false))
13                 {
14                     break;
15                 }
16             }
17             string result=del.EndInvoke(ar);
18             Console.WriteLine(result);
19 
20         }
21 
22         public static string GetTea(string content)
23         {
24             return "茶來了  "+content;
25         }
26     }
View Code

 

非同步回調:這個方式和投票技術有點類似,不過在投票方式中BeginInvoke()方法第三個參數指定了一個方法簽名,而這個方法參數接收IAsyncResult 類型的參數。

 1 public delegate string AsyDelegate(string content);
 2 
 3     public class AsyncresultDelegate
 4     {
 5         public void TestAsync()
 6         {
 7             AsyDelegate del = GetTea;
 8             del.BeginInvoke("hechen", delegate(IAsyncResult ar) {
 9                 Thread.Sleep(5000);
10                 string result = del.EndInvoke(ar);
11                 Console.WriteLine(result);
12             }, null);
13             for (int i = 0; i < 100; i++)
14             {
15                 Console.WriteLine("等待.....");
16                 Thread.Sleep(1000);
17             }
18         }
19 
20         public static string GetTea(string content)
21         {
22             return "茶來了  " + content;
23         }
24     }
View Code

 


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

-Advertisement-
Play Games
更多相關文章
  • 原文:https://www.codeproject.com/articles/85296/important-uses-of-delegates-and-events 原文作者: Shivprasad koirala 介紹 在這篇文章中, 我們會嘗試著去理解delegate能解決什麼樣的問題, 然 ...
  • 我們利用LoadRunner可以對Web應用系統進行性能壓力測試,本篇博客將和大家介紹下LoadRunner 12的下載和安裝,在後續的博客中將和大家介紹其使用的方法。 1、LoadRunner 12.02下載地址:https://pan.baidu.com/s/1nuEE4Jn#list/path ...
  • 零、創建一個.Net Core 2.0 的ConsoleApp 應用,建完就是這個樣子了。 添加Log4Net 的引用,(不想看可以不看,個人習慣)Install-Package log4net添加Config文件夾往文件夾裡面添加Log4net.xml(別忘記了設置Copy always)添加Lo ...
  • ②command對象用來操作資料庫。(三個重要的方法:ExecuteNonQuery(),ExecuteReader(),ExecuteScalar()) ⑴以update(改數據)為例,用到ExecuteNonQuery()方法(執行SQL語句,返回受影響行) 點擊事件(button2) 執行前數 ...
  • 本來想用正則Split一下sql語句中簡單場景的的GO,於是用^GO$(配合忽略大小寫和多行模式),可居然連這種情況都搞不掂: 如果刪掉$就能匹配了,但這顯然不是辦法,遂又在VS的C#交互視窗、RegexTester(.net寫的)、chrome控制台等地方試,發現只有chrome能匹配,而只要是基 ...
  • 最近有一個疑問:IList已經繼承了ICollection<T>,而ICollection<T>繼承了 IEnumerable<T>, IEnumerable,那為什麼IList還要繼承 IEnumerable<T>, IEnumerable? 於是我自己寫了介面測試:用dnSpy反編譯看到,Tes ...
  • ASP.NET Core MVC的Model Binding會將HTTP Request數據,以映射的方式對應到參數中。基本上跟ASP.NET MVC差不多,但能Binding的來源更多了一些。本篇將介紹ASP.NET Core的Model Binding。 Model Binding 要接收Cli ...
  • 巨硬build後發了15.7.1滿載期待的升級了。。結果NM淚奔................... 為啥 淚奔? 使用Chrome 調試閃退,MMP ,一想肯定是VS的鍋咯,各種抓頭髮。。 試試看看VS配置發現 ,多了點東西。。 都勾上後,瞬間跑起來了,但是問題來了,每次會新運行一個Chrome ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...