1. 程式人生 > >C#中委託、事件和回撥函式的理解

C#中委託、事件和回撥函式的理解

在C#中我們經常會碰到事件,尤其是在WPF或者WinForm中,窗體載入、或者點選一個按鈕,都會觸發事件。實際上,事件是對委託的封裝。如果不進行封裝,讓委託暴露給呼叫者,呼叫者就可以把委託變數重新引用到新的委託物件,也就刪除了當前要呼叫的方法列表;更糟糕的是,公共的委託成員打破了封裝不僅導致程式碼難以維護和除錯,而且會導致應用程式有安全風險。下面分別說明。

1、委託

委託可以理解為一種協議。委託,是什麼意思呢?舉個例子,你碰到一件事,你需要讓別人來幫你做(可能你還有別的事情要做),這就是委託,把你現在不能做的事讓別人去做。為什麼說委託就像一個協議呢,因為你不想把事情搞砸了,所以你“委託”的這個人做的這件事,你需要給他定一個標準。在C#中就是給所委託的物件定義好籤名,引數有幾個,分別是什麼型別,委託方法需要反饋給你什麼東西(或者不反饋)。從這種意義上理解,委託就像是一種協議。下面是例子。

 1         public delegate int MyDelegate(int x, int y);
 2         class Delegate_Demo
 3         {
 4             static void Main(string[] args)
 5             {
 6                 //例項化被委託者
 7                 Helper helper = new Helper();
 8                 //建立委託物件
 9                 MyDelegate myDele = new
MyDelegate(helper.Add); 10 int sum = myDele(1, 2); 11 Console.WriteLine(sum); 12 } 13 14 } 15 class Helper 16 { 17 public Helper() { } 18 19 public int Add(int num1, int num2) 20 { 21 return
num1 + num2; 22 } 23 }

上述例子中public delegate int MyDelegate(int x, int y);聲明瞭一個委託,告訴被委託者這件事你要這麼幹,我給你兩個整數,你計算他們的和,怎麼計算我不管,計算完之後你把和給我。

2、事件

在某件事情發生時,一個物件可以通過事件通知另一個物件。比如,前臺介面一個求和按鈕被點選了,他通知你,可以把a和b這兩個數相加了。這就是一個事件。可以看出事件是在一個時間節點去觸發另外一件事情,而另外一件事情怎麼去做,他不會關心。就事件來說,關鍵點就是什麼時候,讓誰去做。

在編譯器處理event關鍵字時,會自動提供註冊和登出方法以及任何必要的委託型別成員變數(私有的),因此不能從觸發事件的物件去呼叫它們,event關鍵字就像一個語法糖,節省了我們打字的時間。

定義一個事件有兩步,首先定義一個委託,它包括了這件事的“協議”和委託方法(由誰去做);其次,用event關鍵字和相關委託宣告這個事件。事件像是一個介面,封裝了委託所定的“協議”。由於委託已經定義了協議,剩下的就是按這個協議去辦事,至於怎麼做它並不關心。下面是一個例子。

 1         public delegate int MyDelegate(int x, int y);
 2         class Delegate_Demo
 3         {
 4             //宣告事件
 5             static event MyDelegate myEvent;
 6             static void Main(string[] args)
 7             {
 8                 //交代事件
 9                 myEvent += new Helper().Add;
10                 int sum = myEvent(3, 4);
11                 Console.WriteLine(sum);
12             }
13 
14         }
15         class Helper
16         {
17             public Helper() { }
18 
19             public int Add(int num1, int num2)
20             {
21                 return num1 + num2;
22             }
23         }

從上面可以看出,呼叫者無法訪問委託物件。

3、回撥函式

回撥函式就是把一個方法的傳給另外一個方法去執行。回撥函式只是一個功能片段,由使用者按照回撥函式的呼叫約定來實現的一個函式。先看一個例子。

 1         public delegate int MyDelegate(int x, int y);
 2         class Delegate_Demo
 3         {
 4             //宣告事件
 5             static event MyDelegate myEvent;
 6             static void Main(string[] args)
 7             {
 8 
 9                 int sum = MyAdd(1, 2, new Helper().Add);
10                 Console.WriteLine(sum);
11             }
12             private static int MyAdd(int a, int b, MyDelegate myDele)
13             {
14                 return myDele(a, b);
15             }
16 
17         }
18         class Helper
19         {
20             public Helper() { }
21 
22             public int Add(int num1, int num2)
23             {
24                 return num1 + num2;
25             }
26         }

可以看出,可以把任意一個符合這個委託的方法傳遞進去,意思就是說這部分程式碼是可變的。而設計上有一個抽離出可變部分程式碼的原則,這種用法無疑可以用到那種場合了。

相關推薦

C#委託事件函式理解

在C#中我們經常會碰到事件,尤其是在WPF或者WinForm中,窗體載入、或者點選一個按鈕,都會觸發事件。實際上,事件是對委託的封裝。如果不進行封裝,讓委託暴露給呼叫者,呼叫者就可以把委託變數重新引用到新的委託物件,也就刪除了當前要呼叫的方法列表;更糟糕的是,公共的委託成員打破了封裝不僅導致程式碼難以維護和除

C#委託事件函式

using System;using System.Collections.Generic;using System.Text;namespace TestApp{    ///<summary>/// 委託    ///</summary>///<param name="s1

詳解C#委託事件函式

.Net程式設計中最經常用的元素,事件必然是其中之一。無論在ASP.NET還是WINFrom開發中,窗體載入(Load),繪製(Paint),初始化(Init)等等。“protected void Page_Load(object sender, EventArgs e)”這

JavaScript的引用函式呼叫函式函式

引用函式與呼叫函式的區別 引用函式與呼叫函式的差別與函式名稱後是否附有括號()有關。函式引用只會單獨出現,但函式呼叫則必定後隨括號,很多時候還附有自變數。 舉個例子 // 函式引用 程式碼一 function f(){ var x = 5; retu

c#常量ReadOnlyStatic ReadOnly的差異

在c#中常量中修飾符使欄位或區域性變數保持不變。ReadOnly應用於c#中的欄位,在初始化後值是常量。Static ReadOnly使ReadOnly欄位具有類成員的特性。(可通過類名訪問) 請仔細閱讀關於常量和readonly之間的差異的總結,然後我將試著解釋後面的每一點。 常量與Rea

C#委託事件的學習小結(一)

最近又學習了一些C#的小知識點,在此釋出部落格記錄一下。 一、委託 C#中的委託的關鍵字是delegate,我們可以使用委託型別來將已有的方法例項化出來,也可以將我們自己定義的方法作為引數來傳遞。 例如: private delegate string GetAStri

C++過載覆蓋隱藏的區別,以及適用場景

一、過載、覆蓋和隱藏的區別 二、適用場景 1、過載:   適用於不同的資料型別都需要使用到的功能函式。以資料相加的函式為例,可以在同一個檔案內提供以下的過載函式以支援同樣的功能:   int add(int, int);/*2個整數相加*/   int add(int, int, int);/*3個整數相

C++ceilfloorround的區別

  Math類中提供了三個與取整有關的方法:ceil,floor,round,這些方法的作用於它們的英文名稱的含義相對應 1、ceil的英文意義是天花板,該方法就表示向上取整,Math.ceil(11.3)的結果為12,Math.ceil(-11.6)的結果為-11; 2、floor的英文是地

C#陣列ArrayListList三者的區別

    在C#中陣列,ArrayList,List都能夠儲存一組物件,那麼這三者到底有什麼樣的區別呢。 陣列     陣列在C#中最早出現的。在記憶體中是連續儲存的,所以它的索引速度非常快,而且賦值與修改元素也很簡單。 //陣列 string[] s=new string[

C++基礎之八】函式指標函式

C++很多類庫都喜歡用回撥函式,MFC中的定時器,訊息機制,hook機制等待,包括現在在研究的cocos2d-x中也有很多的回撥函式。1.回撥函式什麼是回撥函式呢?回撥函式其實就是一個通過函式指標呼叫的函式!假如你把A函式的指標當作引數傳給B函式,然後在B函式中通過A函式傳進

C語言實現動態陣列 C語言函式指標函式

實現任意資料型別的動態陣列的初始化,插入,刪除(按值刪除;按位置刪除),銷燬功能。、 動態陣列結構體   實現動態陣列結構體的三個要素:(1)陣列首地址;(2)陣列的大小;(3)當前陣列元素的個數。 1 //動態陣列結構體 2 struct DynamicArray{ 3 void **a

C#二進位制十進位制十六進位制互相轉換的方法

二進位制在C#中無法直接表示,我們一般用0和1的字串來表示一個數的二進位制形式。比如4的二進位制為“100”。下面介紹C#裡面用於進位制轉換的方法。 十進位制轉換為二進位制(int-->stri

Android開發 通過JNI實現JAVA與C/C++程式間的呼叫

       在一些Android應用的開發中,需要通過JNI和 Android NDK工具實現JAVA和C/C++之間的相互呼叫。        Java Native Interface (JNI)標準是java平臺的一部分,它允許Java程式碼和其他語言寫的程式碼進行

C#委託的定義使用

委託 如果我們要把方法當做引數來進行傳遞的話,就要用到委託。 簡單來說,委託是一個型別,這個型別可以賦值一個方法的引用。 宣告委託 在C#中使用一個類分為兩個階段。 首先,定義這個類,告訴編譯器這個類是由什麼欄位和方法組成的。 然後,使用這個類例項化

C#呼叫C/C++ DLL 引數傳遞函式的總結

Int型傳入: Dll端: extern "C" __declspec(dllexport) int Add(int a, int b) {     return a+b; } C#端: [DllImport("aeClient2.0.dll", CallingCo

C++過載覆蓋隱藏的區別

一、過載: 是函式名相同,引數列表不同 過載只是在類的內部存在。但是不能靠返回值型別來判斷。規則如下:1、相同的範圍(在同一個類中)2、函式名字相同3、引數不同4、Virtual關鍵字可有可無、二、覆蓋: 在繼承關係中,子類中定義了與父類同名的虛擬函式,從而子類自己本身定義的

C++coutcinendl的用法

轉自:http://blog.163.com/ac_victory/blog/static/1033187262008112222553105/ 對以上三篇文章,我添加了自己已有的部分知識,並重新地彙總整理 輸入和輸出並不是C++語言中的正式組成成分。C和C++

C#陣列ArrayListList三者的區別 .

    在C#中陣列,ArrayList,List都能夠儲存一組物件,那麼這三者到底有什麼樣的區別呢。 陣列     陣列在C#中最早出現的。在記憶體中是連續儲存的,所以它的索引速度非常快,而且賦值與修改元素也很簡單。 [csharp] view plaincopyprint? <SPAN 

C++使用libuv時對的處理 (2)

# 前情簡介 在完成了第一版的《[在C++中使用libuv時對回撥的處理](https://www.cnblogs.com/ink19/p/13618393.html)》之後,在對專案進行開發的時候,還是感覺有一些難受。 因為在實際操作的時候,需要構建一個結構體,並且需要對這個結構體的記憶體進行管理,非常的

Nodejs學習筆記 day02——REPL函式

  1、REPL(互動式直譯器): Node自帶互動式直譯器: 讀取使用者輸入 ==> 執行輸入的資料結構 ==> 列印輸出結果(迴圈執行,直到使用者按ctrl+c兩下後結束)   變數: var x = 10 //宣告變數並賦值,如果沒有