委托
簡單記錄點東西 適合似懂非懂的朋友看看
委托類型用來定義和響應應用程序中的回調。
借此可以設計各種有面向對象特性的代碼模式。下面要說的事件在我看來就是委托的一種實現,再深一步講,利用委托加事件,是不是可以構建各種所謂的管道框架。
如ASP.NET WebAPI
的管道模型,整個消息處理管道是通過一組有序的HttpMessagHandler
“首尾相連”而成,具體實現“串聯”的是通過DelegatingHandler
這個類型來完成的。即是一組委托鏈
。
最精華的內容您已看完
委托定義 public delegate int DeleName(int x);
名稱
參數
返回值
1、委托簡單示例
DeleName del = M1;
public int M1(int i)
{
...
}
入門理解1:委托是方法的類型,即委托=class,方法=new class()
上面的方法名稱M1只起到傳遞作用時,可以用匿名委托代替:
DeleName del = delegate (int i)
{
...
};
除了用匿名委托,還可以用lamda表達式進行代替:
DeleName del = (int i)=>
{
...
};
在這里也能看出lamda本質就是委托
2、泛型委托
public delegate void MyGenericDelegate1<T>(T arg);
public delegate int MyGenericDelegate2<T,M>(T arg,M name);
MyGenericDelegate1<int> intTarget = new MyGenericDelegate<int>(IntTarget);
static void IntTarget(int arg) => Console.WriteLine($"IntTarget--> {++arg}");
MyGenericDelegate2<int,string> intTarget1 = (int arg,string name) =>
{
return 1;
};
好處:封裝為了復用
看下上面兩個委托的命名:MyGenericDelegate1 MyGenericDelegate2 純粹為了取名而取名,此時我們可以不自己取名。
怎么做呢,C#本身提供了兩個泛型委托可以給我們使用,且可滿足大多數場景。
3、泛型Action<> 和 Func<> 委托
(可指向至多傳遞16個參數的方法)
Action<>:無返回值: 定義 public delegate void Action<...>
public static void Show()
{
// 使用Action<>委托來指向 DisplayMessage()
Action<string, ConsoleColor, int> actionTarget = new Action<string, ConsoleColor, int>(DisplayMessage);
actionTarget("actionTarget", ConsoleColor.Red, 5);
}
// Action<> 委托的一個目標
private static void DisplayMessage(string msg, ConsoleColor txtColor, int printCount)
{
...
}
Func<>:有返回值 public delegate TResult Func<..., out TResult> TResult:返回值類型
Func<int, int, int> funcTarget = new Func<int, int, int>(Add);
funcTarget(1, 2);
static int Add(int x, int y) => x + y;
如果你覺得一個具有自定義名稱的委托更有助於捕獲問題范疇,那么構建自定義委托不過就是一行代碼的事兒。
注:Linq中就大量的用到了 Action<> 和 Func<>。
4、事件
最簡單的說法是:可以把事件看成是委托的一個實例。委托比作類:它定義了函數的簽名(接受什么類型的參數 返回什么類型的值)事件比作委托new出來的一個實例,是具有該委托簽名的具體函數。當然事件和實例也是有區別的:
1、事件這個東西 能容納很多個具體的函數(通過+= -= 增加刪除)。
2、事件有event關鍵字起到了保護作用不允許改變事件的引用。即在聲明事件的類外部不能用=對事件對象賦值
直接看看代碼
public delegate void HelloWorldDelegate(string name);
public class HelloWorldClass2
{
public event HelloWorldDelegate del;//!!!!event修飾了委托對象
public void HelloWorld(string name)
{
//del = (n) => { Console.WriteLine(n); };//在聲明事件的類內部可以用=直接定義事件的引用(賦值)
del(name);
}
}
class Program
{
static void Main(string[] args)
{
HelloWorldClass2 h2 = new HelloWorldClass2();
//h2.del = ByEnglish;//不允許改變事件的引用(不能用=賦值)
h2.del += ByEnglish;//第一種
//手工創建一個委托變量是最直接的方式。但是大多數情況下,我們並不依靠委托對象。我們可以使用C#提供的方法組轉換的方法,它允許我們在調用以委托作為參數的方法時直接提供了與委托期望的簽名想匹配的方法的名稱(返回 void,參數 string),而不是創建委托對象。(所以一般直接用上面這種)
HelloWorldDelegate de = ByChinese;
h2.del += de;//第二種
h2.HelloWorld("mary");
Console.ReadLine();
}
static void ByEnglish(string name)
{
Console.WriteLine("hello,world"+name);
}
static void ByChinese(string name)
{
Console.WriteLine("你好,世界" + name);
}
}
事件默認是個多播委托,什么是多播委托呢?就是上面的h2.del委托容納的方法有多個,ByEnglish跟ByChinese,用+=可以繼續往下延伸。
委托和事件的區別在於,事件是個規約,委托是個實現(當然抽象上的委托也可以不是個具體的實現)。
規約的含義是,我定義了這么個語法,你可以通過+=和-=把委托掛載到這個東西(事件)上,當發生這個事件的時候,我會確保這些委托都被得到調用。但是具體是怎么調用的,你不用關心。
歡迎討論~
感謝閱讀~
個人公眾號: