文章目錄
- 一、什麼是委托?
- 二、委托使用步驟
-
- 1.聲明委托
-
- 1.1執行個體化委托
- 1.2委托調用
- 1.3委托使用場景
- 1.4系統内置委托Action Func
- 1.5 多點傳播委托
- 二、什麼是事件
-
- 1.聲明事件
- 1.1事件調用
-
- 1.3事件使用場景
- 1.4 事件與設計模式
一、什麼是委托?
委托是尋址方法的.Net版本,在C++中,函數指針隻是指向記憶體位置,不是類型安全的。你無法得知這個指針實際指向什麼,參數類型、傳回類型也無從得知。而.Net委托是一個類型安全的類,它定義了傳回類型、參數類型。從IL中看它是繼承至MulticastDelegate,是以委托可以說其實就是個類。
功能上而言:當要把方法作為傳送給其他方法時,就需要使用委托
C#:
IL:上圖代碼在IL編譯後的結果,可知其繼承自父類 MulticastDelegate
二、委托使用步驟
1.聲明委托
定義委托就是告訴編譯器這種類型的委托表示那種類型的方法
//聲明一個委托
public delegate void Voiddelegate( int x);// 聲明一個委托,委托所包含的方法帶有一個int參數,并且傳回Void
public delegate void Void_delegate();//委托所包含的方法無參數,并且傳回Void
public delegate int IntDelegate();// 委托所包含的方法無參數,并且傳回int
public delegate int Int_Delegate(int x);// 委托所包含的方法帶有一個int參數,并且傳回Void
定義委托等同于定義一個新類,是以可以在任何地方定義、加上任何修飾符public、private…
1.1執行個體化委托
執行個體化時必須傳遞一個和委托的參數及傳回值相同的方法
IntDelegate intDelegate = new IntDelegate(test);
public static int test(){
return 1;
}
1.2委托調用
intDelegate.Invoke();
intDelegate();//兩者等價,可以省略invoke
//參數①:AsyncCallback是異步完成的回調方法。
//參數②是使用者自定義對象,該對象将傳遞到回調方法中
intDelegate.BeginInvoke(null, null);//重新開一個新線程去執行方法
intDelegate.EndInvoke(null);//檢測異步調用的結果,通常放在回掉函數中
1.3委托使用場景
用于解耦、減少代碼不穩定性、減少重複代碼
public class A{
public delegate void Str_Delegate(string type);
public void sayCat(string type){
Console.WriteLine("cat:"+type);
}
public void sayDog(string type)
{
Console.WriteLine("Dog:" + type);
}
public void Say(string type,Str_Delegate str_Delegate){
//可以在此處添加公共邏輯,避免重複代碼
str_Delegate.Invoke(type);
}
}
--------------
static void Main(string[] args)
{
A a = new A();
a.Say("leslie", new A.Str_Delegate(a.sayCat));
Console.Read();
}
結果:
1.4系統内置委托Action Func
Action:沒有傳回值,參數可有可無,最多支援十六個參數
Func:必須有傳回值,參數可有可無,最多支援十六個參數,最後一個參數為傳回值類型
public class A
{
public Action Str_Delegate;
public void sayCat()
{
Console.WriteLine("cat:");
}
public void sayDog()
{
Console.WriteLine("Dog:");
}
public void Say()
{
Console.WriteLine("start say");
Str_Delegate.Invoke();
}
}
static void Main(string[] args)
{
A a = new A();
a.Str_Delegate +=a.sayDog;
a.Str_Delegate += a.sayCat;
a.Say();
Console.Read();
}
1.5 多點傳播委托
任何一個委托都是多點傳播委托,因為繼承自父類 MulticastDelegate
static void Main(string[] args)
{
inInvoke(null,null);
A a = new A();
A.Str_Delegate str_Delegate=a.sayCat;
str_Delegate += a.sayDog;
str_Delegate.Invoke("leslie");
Console.Read();
}
–
通過+=、-=進行對一個委托執行個體進行添加和移除方法。增加方法後委托就成了一個方法鍊,順序執行
str_Delegate += a.sayDog;
//此處不能移除sayDog方法,因為屬于兩個不同的執行個體
str_Delegate -= new A().sayDog;
注意:lamda表達式在多點傳播委托中也不能被移除
Func委托在形成方法鍊後隻能擷取到最後一個方法的傳回值
二、什麼是事件
事件是委托的一種應用場景,相比與委托它更安全,可以限定權限,無法在定義類的外部進行invoke調用。
1.聲明事件
public class A{
//聲明一個事件,其實就是在委托聲明的前面加上一個Event關鍵字
public event Action SayHandler;
public void sayCat(){
Console.WriteLine("cat:");
}
public void sayDog()
{
Console.WriteLine("Dog:");
}
public void Say(){
//事件調用,隻能在類内部進行
SayHandler?.Invoke();
}
}
1.1事件調用
static void Main(string[] args)
{
A a = new A();
a.SayHandler += a.sayCat;
a.SayHandler += a.sayDog;
a.SayHandler.invoke();//報錯,不能在聲明類外進行調用
a.SayHandler = null;//報錯,不能在聲明類外設為null;
Console.Read();
}
注意:多點傳播委托和事件使用時,一次調用隻能傳給這些委托的方法相同的參數。 如果想要再調用每個方法時,參數值都不同,可以采用foreach語句,枚舉每一個調用,單獨調用相應的方法進行傳參。
1.3事件使用場景
事件通常用于winform、WPF、封裝公共邏輯(滑鼠懸停、控件變色等)
static void Main(string[] args)
{
A a = new A();
a.SayHandler += a.sayCat;
a.SayHandler += a.sayDog;
a.Say();
Console.Read();
}
public class A{
public delegate void Str_Delegate(string type);
public event Action SayHandler;
public void sayCat(){
Console.WriteLine("cat:");
}
public void sayDog()
{
Console.WriteLine("Dog:");
}
public void Say(){
Console.WriteLine("start say");
SayHandler?.Invoke();
}
}
當調用say方法時,注冊在sayhandler事件上的方法也會一并觸發
1.4 事件與設計模式
1.3中的代碼其實像極了觀察者模式、釋出/訂閱
public event Action sayHanlder就是一個channel。
a.sayHandler += a.cat就是 subscribe 對 channel的訂閱。
public void Say() 就是publisher。
将1.3的代碼換成觀察者模式:
public class A{
public List<Action> Actions = new List<Action>();
public void sayCat(){
Console.WriteLine("cat:");
}
public void sayDog()
{
Console.WriteLine("Dog:");
}
public void Say(){
Console.WriteLine("start say");
Actions.ForEach(item => { item.Invoke(); });
}
static void Main(string[] args)
{
A a = new A();
a.Actions.Add(a.sayCat);
a.Actions.Add(a.sayDog);
a.Say();
Console.Read();
}
是以兩者其實沒什麼不同,隻是在C#中的一種應用而已。