每個編程者在項目中必定繞不開的話題:委托和事件。對於初學者來說,總會感覺有些難以理解,或者說無法自己隨意運用。本文對委托、事件做一個詳細的講解,即是基礎知識的自我溫故,同時亦是記錄。篇幅有些長,如果認真閱讀,相信你會有所收獲。
《Introducing Visual C# 2010》(Adam Freeman著,Apress出版)一書的第10章中有這樣的介紹:
Delegates are special types thatencapsulate a method, similar to function pointers found in other programminglanguages. Delegates have a number of uses in C#, but you are most likely toencounter a special type of delegate—the event. Events make notifyinginterested parties simple and flexible, and I’ll explain the convention fortheir use later in the chapter.
委托是封裝方法的特殊類型,它類似於其它編程語言中的函數指針。委托在C#中有大量運用,但你最可能遇到的是一種特殊的委托類型— 事件。事件使得對相關部件的通知變得簡單而靈活,本章后面將解釋其使用約定。
I’ll also explain the Func and Action typesthat let you use delegates in a more convenient form and that are usedextensively in some of the latest C# language features, such as parallelprogramming. We’ll finish up this chapter with a look at anonymous methods andlambda expressions, two C# features that let us implement delegates withouthaving to define methods in our classes.
我也會解釋Func和Action類型,它們讓你以更方便的形式使用委托,而且在一些最新的C#特性中也有廣泛使用,如並行編程。本章最后考察匿名方法和lambda表達式,這是讓我們不必在類中定義方法就可以使用委托的兩個C#特性。
委托:
委托定義:將函數作為另一個函數的參數進行調用。另外的解釋:當一個類或者是進程需要調用另外一個方法時,需要借助另外的類或者是進程進行調用,這種機制稱為委托。網上有大牛說:委托可以理解為函數指針,不同的是委托是面向對象、類型安全的。
實現步驟:
1、聲明一個委托類型:
public delegate int CalculateDelegate(int x, int y);
2、定義一個委托對象:
CalculateDelegate calculateDelegate = new CalculateDelegate(Add);
其中Add是委托封裝的方法;
3、執行委托方法:
calculateDelegate(2, 3);
其中委托綁定的方法Add:
public static int Add(int x, int y)
{ return x + y;}
事件:
事件是一種特殊類型的委托
拿winform中button雙擊舉例說明委托可能更加貼切:
聲明一個委托,並聲明一個事件:
public delegate void EventHandler(object sender, EventArgs e); public event EventHandler Click;
綁定一個事件:
this.button1.Click += new System.EventHandler(this.button1_Click);
this.button1_Click是一個方法:
private void button1_Click(object sender, EventArgs e){}
拿一個實際項目舉例說明:
匿名方法:
匿名方法(Anonymous methods) 提供了一種傳遞代碼塊作為委托參數的技術。匿名方法是沒有名稱只有主體的方法。在匿名方法中您不需要指定返回類型,它是從方法主體內的 return 語句推斷的。
在之前講解委托時寫到綁定方法:
CalculateDelegate calculateDelegate = new CalculateDelegate(Add); public static int Add(int x, int y)
{
return x + y;
}
如果使用匿名方法重寫上面的代碼:
CalculateDelegate calculateDelegate = delegate(int x, int y){return x + y;};
可見:匿名方法綁定委托直接省去了編寫一個單獨的方法,使得代碼更為簡潔。
項目中,使用委托時,很多時候編輯器會幫助我們把方法直接放入合適的委托對象中,但有時候編輯器幫助不了我們,比如:Control.Dispatcher.Invoke(delegate). 例如:
this.btnExit .Dispatcher .Invoke (new Action(() => {}));
Lambda表達式:
Lambda 表達式是一種匿名函數,簡單地說,它是沒有聲明的方法,也即沒有訪問修飾符、返回值聲明和名字;
C#的Lambda 表達式都使用 Lambda 運算符 =>,該運算符讀為“goes to”。語法如下:
(object argOne, object argTwo) => {; /*Your statement goes here*/}
用Lambda表達式重寫上面使用匿名方法編寫的委托實例,在匿名方法的基礎上,編寫如下:
方式一:
CalculateDelegate calculateDelegate = (int x, int y) => { return x + y; };
方式二,更簡單的表達:
CalculateDelegate calculateDelegate = (x, y) => { return x + y; };
方式三,再簡單:
CalculateDelegate calculateDelegate = (x, y) => x + y;
從上面可以看出,Lambda僅僅是在匿名方法的基礎上加上 => 符號,但是卻讓整個代碼實現起來顯得更為優雅。
泛型委托:
在.net平台下有Microsoft自帶的泛型委托,如:Action,Action<T>,Fun<T>等。實際使用中,如果需要用到泛型委托,系統內置的委托基本上就能滿足需求了,下面一一介紹它們的原型及調用實例。
Action
系統封裝的Action委托,沒有參數沒有返回值。調用實例為:
public delegate void Action(); static void Main(string[] args)
{
Action action = new Action(Method);
action();
} private static void Method()
{
Console.WriteLine("i am is a action");
}
如果方法的表達很簡單,可以使用Lambda表達式,代碼如下:
Action action = () => { Console.WriteLine("i am is a action"); };
Action<T>
系統封裝的Action<T>委托,有參數但是沒有返回值。調用實例為:
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); static void Main(string[] args)
{
Action<int,int> action = new Action<int,int>(Method);
action(2,3);
} private static void Method(int x,int y)
{
Console.WriteLine("i am is a action");
}
使用Lambda表達式編寫Action<T>代碼如下:
Action<int, int> action = (x, y) => { Console.WriteLine("i am is a action"); };
Fun<T>
系統封裝的Fun<T>委托,有返回值。調用實例為:
public delegate TResult Fun<in T1, in T2, out TResult>(T1 arg1, T2 arg2); static void Main(string[] args)
{
Fun<int, int, bool> fun = new Fun<int, int, bool>(Method);
bool ret = fun(2,3);
} private static bool Method(int x,int y)
{
if (x + y == 5) return true;
else return false;
}
使用Lambda表達式編寫Fun<T>,代碼如下:
Fun<int, int, bool> fun = (x, y) =>
{
if (x + y == 5) return true;
else return false;
};
Fun<T>沒有參數有返回值的情況:
Fun<bool> fun = () =>
{
int x = 4;
int y = 3;
if (x + y == 5) return true;
else return false;
}; //也可以如此編寫Fun<bool> fun = () => false;
多播委托:
最后說下多播委托,所謂多播委托,即 “多路廣播委托”(MulticastDelegate)。從它的名字就可以看出,此種委托可以像廣播一樣將影響信息“傳播”到四面八方。多播委托類擁有一個方法調用列表,調用委托時,它就會逐一調用該列表中的方法,從而實現多重影響。比較簡單,暫不舉例說明了。
本文暫且告一段落,如果想查看更多文章,請關注“小項目筆記”公眾號;
如有疑問:可加入QQ群號:732982683