c#核心基礎-委托

来源:http://www.cnblogs.com/liyongke/archive/2017/02/06/6370129.html
-Advertisement-
Play Games

委托是一個類型。C#中的委托是面向對象的,並且它是類型安全的 當創建委托實例的時候,創建的實例會包含一個調用列表,在調用列表中可以包含多個方法。每個方法稱作一個調用實體。調用實體可以是靜態方法,也可以是實例方法。如果是實例方法,則該調用實體包含調用該實例方法的實例。委托並不關心它所調用方法所屬的類, ...


  委托是一個類型。C#中的委托是面向對象的,並且它是類型安全的 當創建委托實例的時候,創建的實例會包含一個調用列表,在調用列表中可以包含多個方法。每個方法稱作一個調用實體。調用實體可以是靜態方法,也可以是實例方法。如果是實例方法,則該調用實體包含調用該實例方法的實例。委托並不關心它所調用方法所屬的類,它只關心被調用方法與委托的類型是否相容。 下麵是代碼實例:

 1 using System;
 2 namespace LycheeTest{
 3     public delegate void D(int a, int b);
 4     public class Test {
 5         public D myDelegate;
 6         public Test() {
 7             myDelegate = new D(Show1);
 8         }
 9         private static void Show1(int a, int b) {
10             Console.WriteLine("方法 Show1 被調用,兩個實參相加的值是:{0}", a + b);
11         }
12         private void Show2(int a, int b) {
13             Console.WriteLine("方法 Show2 被調用,兩個實參相加的值是:{0}", a + b);
14         }
15         private void Show3(int a, int b) {
16             Console.WriteLine("方法 Show3 被調用,兩個實參相加的值是:{0}", a + b);
17         }
18     }
19     public class Program {
20         static void Main(string[] args) {
21             Test myT = new Test();
22             myT.myDelegate(33, 22);
23             Console.ReadKey();
24         }
25     }
26 
27 }

  這段代碼演示的是最簡單的一種委托形式。委托類型可以定義在類的外部,也可以定義在類的內部。 本段代碼是定義在類的外部。第 3 行代碼定義的就是一個委托類型,委托類型的關鍵字是 delegate,關鍵字前是委托類型的訪問許可權修飾符。關鍵字後是委托類型的返回類型,這個返回類型規定與委托類型相容 的方法的返回類型必須與之相同。返回類型之後是委托類型的名稱。接下來是形參列表,它指定與委托類 型相容的方法的參數類型和個數必須與之相同。第 5 行代碼定義了一個委托類型的變數,它是一個實例欄位,訪問許可權是 public 的。註意委托類型欄位的訪問許可權一定要比委托類型的訪問許可權低或與委托類型的訪問許可權相同才可以。第 9 行、第 12 行和第 15 行代碼定義了三個方法。其中第 9 行代碼是一個靜態方法。因為這段代碼演示的是最簡單的委托使用方法,所以只使用了其中的靜態方法。在第 6 行的構造方法中,實例化了委托類型的變數,註意為委托變數的調用列表添加方法,只需要向其構造方法中傳遞方法名稱即可。這是為委托添加調用方法的最基本的一種方法。第 21 行定義了 Test 類的一個實例,然後第 22 行調用了類的委托成員。在調用委托成員的時候,需要向其形參列表傳遞實參。這就是最基本的委托的使用方法。這段代碼的執行結果如下:

 

方法 Show1 被調用,兩個實參相加的值是:55

 下麵再介紹一種委托類型的使用方法,實例代碼如下:

 1 using System;
 2 namespace LycheeTest {
 3     public delegate void D(int a, int b);
 4     public class Test {
 5         public static void Show1(int a, int b) {
 6             Console.WriteLine("方法 Show1 被調用,兩個實參相加的值是:{0}", a + b);
 7         }
 8         public void Show2(int a, int b) {
 9             Console.WriteLine("方法 Show2 被調用,兩個實參相加的值是:{0}", a + b);
10         }
11         public void Show3(int a, int b) {
12             Console.WriteLine("方法 Show3 被調用,兩個實參相加的值是:{0}", a + b);
13         }
14     }
15     public class Program {
16         static void Main(string[] args) {
17             Test myT = new Test();
18             D myDelegate = new D(Test.Show1);
19             D myDelegate1 = new D(myT.Show2);
20             D myDelegate2 = new D(myT.Show3);
21             myDelegate(22, 33);
22             myDelegate1(33, 44);
23             myDelegate2(55, 66);
24             Console.ReadKey();
25         }
26     }
27 
28 }

  這段代碼取消了類中的委托類型欄位,而是將委托類型作為一個類來看待。在包含入口點方法的類中,首先第 17 行定義了 Test 類的一個變數並做了實例化。因為要向委托傳遞類的實例方法,所以必須有類的實 例存在,才能引用類的實例方法。第 18 行定義了一個委托類型的變數,並實例化,這裡需要註意,因為委托並不是類中的一個成員了, 所以向其構造方法傳遞靜態方法的時候,需要以類名引用。第 19 行也定義了一個委托類型的變數,在向其傳遞實例方法的時候,需要以類的實例來引用。第 20 行代碼的情況同第 19 行代碼一樣。在向委托傳遞方法的時候,需要傳遞方法名,而不需要方法的形參列表。第 21 行到第 23 行是對委托的調用,這時要為其傳遞方法的實參。這段代碼的執行結果如下:

方法 Show1 被調用,兩個實參相加的值是:55 
方法 Show2 被調用,兩個實參相加的值是:77 
方法 Show3 被調用,兩個實參相加的值是:121

 委托的訪問修飾符

  當委托位於類的外部時,可以使用的訪問修飾符包括 public 和 internal。如果什麼也不寫,預設是internal 的。當委托位於類的內部時,可以使用的訪問修飾符包括 public、protected、internal、protected 

 1 using System;
 2 namespace LycheeTest{
 3     public class Test {
 4         protected delegate void D(int a, int b);
 5         private delegate void D1(int a, int b);
 6         protected internal delegate void D2(int a, int b);
 7         internal delegate void D3(int a, int b);
 8         private D myD;
 9         private D1 myD1;
10         private D2 myD2;
11         private D3 myD3;
12         public Test() {
13             myD = new D(Show1);
14             myD1 = new D1(Show1);
15             myD2 = new D2(Show1);
16             myD3 = new D3(Show1);
17         }
18         public static void Show1(int a, int b) {
19             Console.WriteLine("方法 Show1 被調用,兩個實參相加的值是:{0}", a + b);
20         }
21         public void Show2(int a, int b) {
22             Console.WriteLine("方法 Show2 被調用,兩個實參相加的值是:{0}", a + b);
23         }
24         public void Show3(int a, int b) {
25             Console.WriteLine("方法 Show3 被調用,兩個實參相加的值是:{0}", a + b);
26         }
27         public void Use() {
28             myD(11, 12);
29             myD1(22, 45);
30             myD2(55, 78);
31             myD3(345, 100);
32         }
33     }
34     class Test1: Test {
35         private D Test1D;
36         private D2 Test1D2;
37         private D3 Test1D3;
38         public Test1() {
39             Test1D = new D(Test.Show1);
40             Test1D2 = new D2(Test.Show1);
41             Test1D3 = new D3(Test.Show1);
42         }
43         public void Use1() {
44             Test1D(22, 45);
45             Test1D2(44, 45);
46             Test1D3(77, 78);
47         }
48     }
49     public class Program {
50         static void Main(string[] args) {
51             Test1 myT1 = new Test1();
52             myT1.Use();
53             myT1.Use1();
54             Console.ReadKey();
55         }
56     }
57 }

  代碼的第 4 行在類的內部定義了委托類型,它作為類的成員定義,訪問許可權是 protected,它可以被本類內部訪問,也可以被派生類訪問。代碼的第 5 行定義的委托類型,訪問許可權是 private 的,它只可以被本類內部訪問。代碼的第 6 行定義的 protected internal 訪問許可權的委托類型,可以被本程式集訪問, 還可以被派生類訪問,而不管派生類位於哪個程式集。第 7 行定義的委托類型是 internal 的,它只可以被本程式集訪問。因為所有這幾種委托類型都可以被本類內部訪問,所以第 10 行到第 13 行定義了它們的變數。第 12 行的實例構造方法中,對這四個委托類型的變數進行了實例化,併為它們的調用列表加入了方法 Show1。Show1 是一個靜態方法,但是在類內部傳入委托類型的構造方法時,不需要使用類名引用。第 27 行定義了實例方法,在方法內部調用了這四個委托,併為其傳入實參。第 34 行代碼又定義了一個類,它繼承自基類 Test。因為基類中的委托類型只有 D、D2 和 D3 可以被派生類訪問,所以第 35 行到第 37 行定義了它們的變數。註意,雖然它們和基類中的委托變數是同一種類型, 但是它們是不同的委托。在第 38 行的實例構造方法中,為這三個委托類型的變數創建實例,併為其調用列表加入方法,因為靜態方法 Show1 也被派生類所繼承,所以這裡傳入的方法名,可以使用類名引用,也可以不使用類名引用。 第 43 行定義了一個實例方法,方法內部調用了這三個委托,併為其傳入實參。第 51 行定義了派生類的實例,然後調用實例方法Use和Use1。這段代碼的執行結果如下:

方法 Show1 被調用,兩個實參相加的值是:23    
方法 Show1 被調用,兩個實參相加的值是:67 
方法 Show1 被調用,兩個實參相加的值是:133
方法 Show1 被調用,兩個實參相加的值是:445 
方法 Show1 被調用,兩個實參相加的值是:67 
方法 Show1 被調用,兩個實參相加的值是:89 
方法 Show1 被調用,兩個實參相加的值是:155

  因為 D 和 D2 的訪問許可權被定義成了 protected 和 protected internal。所以下麵來驗證在其它程式集中是否可以訪問它們。首先要將本段代碼中的包含 Main 方法的類去掉,然後在它的項目屬性中將它改變為類庫。接下來新建一個控制台項目,並物理上引用這個類庫。控制台項目的代碼如下:

 1 using System;
 2 using LycheeTest;
 3 namespace LycheeTest1{
 4     class Program: Test {
 5         private D pD;
 6         private D2 pD2;
 7         public Program() {
 8             pD = new D(Show1);
 9             pD2 = new D2(Show1);
10         }
11         public void Use3() {
12             pD(34, 33);
13             pD2(12, 11);
14         }
15         static void Main(string[] args) {
16             Program p = new Program();
17             p.Use3();
18             Console.ReadKey();
19         }
20     }
21 }

  因為第 3 行代碼的命名空間和類庫的命名空間是兩個獨立的命名空間,它們的成員不位於同一個命名空間內。所以在一個命名空間內引用另一個命名空間的成員時,需要加上另一個命名空間的名稱進行引用。 為了代碼編寫的方便,第 2 行代碼首先引用了類庫的命名空間。第 4 行代碼定義了一個類,它繼承自基類 Test。因為是派生類,所以對於委托類型 D 和 D2 都可以訪 問。第 5 行代碼和第 6 行代碼分別定義了 D 和 D2 的兩個變數。第 7 行的實例構造方法對這兩個變數進行了實例化,併為其傳入方法 Show1。因為 Show1 方法被繼承了下來,所以這裡不需要類名引用。第 11 行代碼定義了一個實例方法,它的作用是調用這兩個委托,併為其傳入實參。第 16 行代碼定義了本類的一個實例,並調用了實例方法 Use3。這段代碼的執行結果如下:

方法 Show1 被調用,兩個實參相加的值是:67
方法 Show1 被調用,兩個實參相加的值是:23 
  類Test中的委托類型D2和D3都具有internal許可權,現在來驗證一下,對於一個同一程式集中的非派生類是否可以訪問它們。首先將類庫更改回控制台項目,然後增加一個類,這個類對於Test類來說是獨立的。它們之間只是位於一個程式集內,彼此沒有繼承關係。代碼如下:
 1 using System;
 2 namespace LycheeTest {
 3     public class Test {
 4         protected delegate void D(int a, int b);
 5         private delegate void D1(int a, int b);
 6         protected internal delegate void D2(int a, int b);
 7         internal delegate void D3(int a, int b);
 8         private D myD;
 9         private D1 myD1;
10         private D2 myD2;
11         private D3 myD3;
12         public Test() {
13             myD = new D(Show1);
14             myD1 = new D1(Show1);
15             myD2 = new D2(Show1);
16             myD3 = new D3(Show1);
17         }
18         public static void Show1(int a, int b) {
19             Console.WriteLine("方法 Show1 被調用,兩個實參相加的值是:{0}", a + b);
20         }
21         public void Show2(int a, int b) {
22             Console.WriteLine("方法 Show2 被調用,兩個實參相加的值是:{0}", a + b);
23         }
24         public void Show3(int a, int b) {
25             Console.WriteLine("方法 Show3 被調用,兩個實參相加的值是:{0}", a + b);
26         }
27         public void Use() {
28             myD(11, 12);
29             myD1(22, 45);
30             myD2(55, 78);
31             myD3(345, 100);
32         }
33     }
34 
35     class Test1 {
36         private Test.D2 tD2;
37         private Test.D3 tD3;
38         public Test1() {
39             tD2 = new Test.D2(Test.Show1);
40             tD3 = new Test.D3(Test.Show1);
41         }
42         public void Use3() {
43             tD2(34, 33);
44             tD3(22, 21);
45         }
46     }
47     public class Program {
48         static void Main(string[] args) {
49             Test1 myT1 = new Test1();
50             myT1.Use3();
51             Console.ReadKey();
52         }
53     }
54 }

  這段代碼中,原來的類Test沒有進行修改。在第35行上,定義了一個類,它是一個相對於Test類來說獨立的類。它們的關係僅限於同在一個程式集內。第 36 行代碼和第 37 行代碼定義了委托類型D2和D3的兩個變數。這裡需要註意,因為這兩個類不是繼承關係,所以要引用Test類中的這兩個委托類型需要使用Test類的類名進行引用。第 38 行代碼是實例構造方法,在構造方法中將委托實例化。實例化委托類型的時候,仍然需要使用類名引用委托類型名,傳遞的方法名也是如此。第 行42 定義了一個實例方法,它調用了委托,併為其傳入了實參。第 49 行代碼定義了類Test1的一個實例,然後第 61 行調用類的實例方法。這段代碼的執行結果如下:

方法 Show1 被調用,兩個實參相加的值是:67 
方法 Show1 被調用,兩個實參相加的值是:43 

 


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

-Advertisement-
Play Games
更多相關文章
  • 本文供實習司機快速上手log4net最基本功能,共4步,3分鐘搞定。 一、添加log4net.dll引用,可使用nuget安裝或直接引用文件 二、添加配置 在app.config或web.config添加如下配置。註意<configSections> 必須放在最上方。 三、項目AssemblyInf ...
  • 1. 概述 依賴屬性(DependencyProperty)是UWP的核心概念,它是有DependencyObject提供的一種特殊的屬性。由於UWP的幾乎所有UI元素都是集成於DependencyObject的FramewordElement,並且這些UI元素的幾乎所有屬性及它們出現在XAML中的 ...
  • 本篇博客轉載:http://www.cnblogs.com/freeliver54/archive/2009/02/11/1388173.html 本次示例效果如下:Form1為父窗體(包含textBox1、button1)Form2為子窗體(包含textBox2、button2) 父窗體給子窗體傳 ...
  • 和大家分享下當前OSS開源項目的進度情況: 一. OSS.Common 【開源中國】 【github】 經過昨天的努力,oss.common項目初步完成了對.net standard的支持,遷移過程本周以新文章的形式開放給大家,當前解決方案有兩個: OSS.Common.NET40 - 針對原來.n ...
  • .net體系經過十幾年發展,發生了很多變化。特別是在最近兩年,隨著開源和跨平臺的發展,衍生出很多概念,像標準庫,可移植庫,.Net Core等,相信有不少同學對他們之間的關係是有一些困惑的,這裡我從基礎概念,跨框架開發的註意事項等,對.net的平臺和相關概念做一個普及分享。此分享是從個人的知識體系中 ...
  • ServerSuperIO 3.2版本以前,設備數據僅支持Xml序列化的方式,如果以其他方式存儲數據,那麼只能把持久化操作寫在設備驅動中,本質上失去了模塊化的靈活性。3.2 版本以後增加了數據持久化介面,方便支持多種形式存儲設備的參數數據和實時數據,3.2版本里現在僅支持Xml序列化的方式,後期會支... ...
  • "ABP入門系列目錄——學習Abp框架之實操演練" "源碼路徑:Github LearningMpaAbp" 一、AbpSession是Session嗎? 1、首先來看看它們分別對應的類型是什麼? 查看源碼發現 是定義在Controller中的類型為 的屬性。 再來看看 是何須類也,咱們定位到 中看 ...
  • ThreadPool線程池的主要方法: 1. public static Boolean QueueUserWorkItem(WaitCallback wc, Object state); WaitCallback回調函數:通過將一些回調函數放入線程池中讓其形成隊列,然後線程池會自動創建或者復用線程 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...