1. 程式人生 > >c#的委託(代理)和事件

c#的委託(代理)和事件

一、代理

首先我們要弄清代理是個什麼東西。別讓一串翻譯過來的概念把大家搞暈了頭。
有的文章把代理稱委託、代表等,其實它們是一個東西,英文表述都是“Delegate”。由於沒有一本權威的書來規範這個概念,所以現在網上對它的稱謂不一。本文我將以“代理”來稱謂Delegate。
代理是什麼呢?我認為“代理就是用來定義指向方法的引用”。下面我們就通過類來理解代理。
如:
Ren r = new Ren("車延祿");
上面的程式碼,就是使用Ren這個類定義了一個指“車延祿”這個物件例項的一個引用。
也可以這樣理解:用Ren類定義的變數r,指向一個“車延祿”物件的例項。
類所定義的變數指向的是一個物件,代理所定義的變數指向的是個方法,當然這個方法可以是靜態方法也可以是例項方法。對代理引用的呼叫就是對代理所指向方法的呼叫。
1.代理宣告的語法:


[public/private] delegate <返回值型別> <代理名稱>(<引數列表>);

[public/private]:訪問修飾符。
delegate:代理宣告關鍵定,相當於類宣告的Class關鍵定
<返回值型別>:代理所指向的方法的返回值型別
<代理名稱>:代理型別的名稱
<引數列表>:代理所的指向的方法的引數列表。


要想使代理物件能夠指向一個方法,那這個方法的要滿足兩個條件
a.方法返回型別要與delegate宣告中的“返回值型別”一致。
b.方法的形參形表要與delegate宣告中的“引數列表”一致。


如:
delegate void MyDelegate(string str,int index);

該代理宣告表示:該代理指向的方法必須是返回空型別,並且擁有兩個引數,第一個是字串型別,第二個是整型。
2.代理“例項化”:
代理宣告相當於類的定義。有了類的定義後我們要還需生成這個類的物件;同樣有了代理的宣告我們還需要“例項化”代理

如:MyDelegate md = new MyDelegate(Show);

這裡的md就是代理變數。在代理的“例項化”的時候必須在建構函式中傳入一個方法名。這個方法名就是該代理指向的方法,當然該方法的返回值型別與引數型別一定要與代理的宣告一致。

Show方法定義如下:
public static void Show(string str, int index)
{
Console.WriteLine("Show"+str+index.ToString());
}

3.代理的呼叫:
md("hello world",22);
此時呼叫的就是md這個代理變數所指向的Show方法。
4.例子:
delegate void MyDelegate(string str,int index);    //宣告代理
class Test
{
public static void Show(string str, int index)     //宣告方法
{
Console.WriteLine("Show"+str+index.ToString());
}
public static void Main(string[] args)
{
MyDelegate md = new MyDelegate(Show); //1.例項化代理,傳入方法
md("hello world",22);                                    //2.傳入引數
}
}

5.代理的應用:
代理的主要應用就是在DotNet中的事件處理,所以要想研究事件我們必須要理解代理的概念。有的文章使用代理進行氣泡排序,我感覺這沒必要,因為不用代理我也可以排序,更況且在C#語法中也不需要我們手動編寫氣泡排序程式碼。
關於代理,大家要理解代理是個什麼東西,並且能夠寫一個簡單的代理示例就可以了。

二、多播代理
上面我們講的代理是一個代理物件指向一個方法,在呼叫該代理物件的時候就會呼叫它所指向的方法。多播代理就是為一個代理掛接上多個方法,當執行該代理的時候就會依次執行該代理上掛接的方法。
1.多播代理的宣告與上面講得基本上一樣:

[public/private] delegate void <代理名稱>(<引數列表>);

只有一點不一樣的就是,多播代理所指向的方法應當是void型別
2.多播代理“例項化”
多播代理“例項化”與上面講得一樣,在此不多說了。

如:MyDelegate md = new MyDelegate(Show);

3.多播代理掛接多個方法。
多播代理可以使用 += 運算子掛接多個方法,也可以使用 -= 運算子從掛接列表中刪除相應的掛接方法。

如:
delegate void MyDelegate(string str,int index);
class Test
{
public static void Show(string str, int index)
{
Console.WriteLine("Show"+str+index.ToString());
}
public static void TestInt(string str, int index)
{
Console.WriteLine("Testint");
}
public static void Main2(string[] args)
{
MyDelegate md = new MyDelegate(Show);  //傳入方法
md += new MyDelegate(TestInt);                   //傳入另一個方法
md("hello world",22);
}
}

在上面這個例子當中有兩個方法(Show和TestInt)符合MyDelegate代理的簽名,如果要把這兩個方法掛接到我們一個代理變數上去的話,就得用 += 運算子了。
MyDelegate md = new MyDelegate(Show);
md += new MyDelegate(TestInt);

這裡的md代理變數上先掛接了Show方法,再掛接TestInt方法。當執行md("hello world",22)的時候會先呼叫Show方法,再呼叫TestInt方法。
事件本身就是一種多播代理

    三、事件:    1.用執行事件傳入引數     2.用註冊事件傳入方法
C#中的事件就是代理的一個變數。
它和屬性、方法一樣,都是類的成員。只不過事件是指向一個方法,當事件被觸發時,就會執行物件的相關方法。
事件的這種對方法的引用並不是寫死在程式碼裡面的,而是可以進行更改的。闢如:我們在DotNet中按鈕的OnClick事件,它可以指向符合OnClick事件簽名的任何一個方法。
1.事件的定義使用event關鍵字:
public event CryHandler DuckCryEvent;

其中的CryHandler是一個delegate。從上面的程式碼我們可以看出來:事件就是一個代理型別的變數。
private delegate void CryHandler();
2.指定事件處理程式:
指定事件處理程式就是為事件掛接方法的過程。
DuckCryEvent +=new CryHandler(Cry);   //註冊事件,傳入方法
public void Cry()
{
Console.WriteLine("我是一隻小鴨,呀依呀依呀....");
}


3.執行事件
執行事件就是呼叫事件所指向方法的過程。一般對事的執行程式碼寫在相應的方法或屬性中,如果方法或屬性被呼叫時就觸發事件。
public void BeShaked()
{
DuckCryEvent();
}


4.完整的例子:
//事件用到的代理,以般以×××Handler的格式進行命名
private delegate void CryHandler();             //無參代理
//玩具小鴨的類
class Duck
{
  //定義小鴨的唱歌事件
public event CryHandler DuckCryEvent;
public Duck()
{
  //把小鴨唱歌的事件掛接到Cry方法上
DuckCryEvent +=new CryHandler(Cry); //註冊事件,傳入方法
}
//小鴨唱歌事件對應的處理方法
public void Cry()
{
Console.WriteLine("我是一隻小鴨,呀呀呀....");
}
//小鴨被搖動
public void BeShaked() //執行方法,引發cry事件
{

DuckCryEvent();                                  //執行事件,傳入引數
}
}
class Class2
{
public static void Main3(string[] args)
{
  //買一隻小鴨
Duck d = new Duck();
//搖一搖小鴨,它就會調觸發小鴨的Cry事件,小鴨就會唱歌