c# delegate和event的使用說明

delegate是什麼

委托(delegate) 是存有對某個方法的引用的一種引用類型變量,引用可在運行時被改變。如果不好理解,可以把委托理解成為函數指針,但它們是有區別的。

delegate和C++中的函數指針:

函數指針隻能指向靜態函數,而delegate既可以引用靜態函數,又可以引用非靜態成員函數。在引 用非靜態成員函數時,delegate不但保存瞭對此函數入口指針的引用,而且還保存瞭調用此函數的類實例的引用。

其次,與函數指針相 比,delegate是面向對象、類型安全、可靠的受控(managed)對象。也就是說,runtime能夠保證delegate指向一個有效的方法, 你無須擔心delegate會指向無效地址或者越界地址。

實例化委托:一旦聲明瞭委托類型,委托類型必須要通過new關鍵字來創建(相當於面向對象中的實例化一個對象),當創建委托時,傳遞到new語句中的參數就像方法的調用一樣書寫, 但是不帶參數。

// 委托的聲明
public delegate void PrintSting(string s); 
//實例化委托
PrintSting ps=new PrintString(WriteToScreen);

匿名方法:

本來委托定義(聲明)好之後,還得再單獨定義委托需要使用的方法。比如你定義瞭一個計算器的委托, 你還需要重新寫計算加減乘除的方法瞭來供計算器委托來使用。這時候我們就想到瞭匿名方法。

用匿名方法就不需要再單獨寫加減乘除這些方法瞭,隻需要在匿名方法的方法體內實現這些邏輯就好瞭。例子如下:

delegate int calculator(int x, int y); //委托類型
static void Main(string[] args)
{
    //創建委托對象(確定與哪些方法進行綁定),委托實例名=new 委托名(某個類的方法,本例與加法向綁定
    calculator Adding =delegate( int x, int y){ return x+y; };
    calculator Moveing = delegate(int x, int y){ return x - y; };
    calculator Multiply = delegate(int x, int y) { return x * y; };
    calculator Divide = delegate(int x, int y) { return x / y; };
 
    Adding(4, 4);//8
    Moveing(4, 4);//0
    Multiply(4, 4);//16
    Divide(4, 4);//1
}

event是什麼

我們可以把事件編程簡單地分成兩個部分:事件發生的類(發佈器:publisher)和事件接收處理的類(訂閱器:subscriber)。事件使用 發佈-訂閱(publisher-subscriber) 模型。

事件發生的類就是說在這個類中觸發瞭一個事件,但這個類並不知道哪個個對象或方法將會加收到並處理它觸發的事件。所需要的是在發送方和接收方之間存在一個媒介。

這個媒介在.NET Framework中就是委托(delegate)。

在事件接收處理的類中,我們需要有一個處理事件的方法。

public class A
{
    public delegate void EventHandler(object sender);
    public event EventHandler a;
 
    public void Run()
    {
        Console.WriteLine("Trigger an event.");
        a(this);
    }
}
 
class B
{
    public B(A a)
    {
        a.a += new A.EventHandler(this.b);
    }
    private void b(object sender)
    {
        Console.WriteLine("Received and handled an event." );
        Console.Read();
    }
}

event和delegate的差異

event是一種特殊的delegate。同為public類型,對於delegate,我們在定義它的類外,不僅可以采用 += 和-=的運算符號,還可隨時調用;但是對於event,在類外隻能采用 += 和-=的運算符號,不能調用,也就是event把它本身的invoke函數和括號調用的函數變成擁有這個event類的私有函數。

event

event隻能被本類調用,其他的即使該類的派生類也不行,如果非要調用類內部的event,可以先聲明一個方法,在該方法中調用event。

Action

Action是一個泛型的委托,其內部即使用delegate去實現,當普通的delegate定義的參數與Action個數、類型一致時,兩者實現的功能是一樣的。隻是Action的方式更加簡潔、規范。

Action與delegate更重要的一個區別在於泛型,即Action的內部使用瞭泛型+委托,且泛型的方法的參數個數可擴展到16個。微軟.net corefx中定義的Action內部代碼如下:

namespace System
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]
    public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
}

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。