委託和事件這兩個概念是徹底配合的。委託僅僅是函數指針,那就是說,它可以引用函數,經過傳遞地址的機制完成。委託是一個類,當你對它實例化時,要提供一個引用函數,將其做爲它構造函數的參數。事件則是委託的一種表現形式。數據庫
委託的聲明:[修飾符] delegate 返回類型 委託名(參數列表); 網絡
簡單的委託異步
using System; using System; using System.Collections.Generic; using System.Text; namespace TestApp { /// <summary> /// 委託 /// </summary> /// <param name="s1"></param> /// <param name="s2"></param> /// <returns></returns> public delegate string ProcessDelegate(string s1, string s2); class Program { static void Main(string[] args) { /* 調用方法 */ ProcessDelegate pd = new ProcessDelegate(new Test().Process); Console.WriteLine(pd("Text1", "Text2")); } } public class Test { /// <summary> /// 方法 /// </summary> /// <param name="s1"></param> /// <param name="s2"></param> /// <returns></returns> public string Process(string s1, string s2) { return s1 + s2; } } }
泛型委託async
using System; using System.Collections.Generic; using System.Text; namespace TestApp { /// <summary> /// 委託 /// </summary> /// <param name="s1"></param> /// <param name="s2"></param> /// <returns></returns> public delegate string ProcessDelegate<T,S>(T s1, S s2); class Program { static void Main(string[] args) { /* 調用方法 */ ProcessDelegate<string,int> pd = new ProcessDelegate<string,int>(new Test().Process); Console.WriteLine(pd("Text1", 100)); } } public class Test { /// <summary> /// 方法 /// </summary> /// <param name="s1"></param> /// <param name="s2"></param> /// <returns></returns> public string Process(string s1,int s2) { return s1 + s2; } } }
委託的回調方法ide
using System; using System.Collections.Generic; using System.Text; namespace TestApp { /// <summary> /// 委託 /// </summary> /// <param name="s1"></param> /// <param name="s2"></param> /// <returns></returns> public delegate string ProcessDelegate(string s1, string s2); class Program { static void Main(string[] args) { /* 調用方法 */ Test t = new Test(); string r1 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process1)); string r2 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process2)); string r3 = t.Process("Text1", "Text2", new ProcessDelegate(t.Process3)); Console.WriteLine(r1); Console.WriteLine(r2); Console.WriteLine(r3); } } public class Test { public string Process(string s1,string s2,ProcessDelegate process) { return process(s1, s2); } public string Process1(string s1, string s2) { return s1 + s2; } public string Process2(string s1, string s2) { return s1 + Environment.NewLine + s2; } public string Process3(string s1, string s2) { return s2 + s1; } } }
事件的聲明:[修飾符] event 委託名 事件名; 函數
事件應該由事件發佈者觸發,而不該該由客戶端(客戶程序)來觸發。注意這裏術語的變化,當咱們單獨談論事件,咱們說發佈者(publisher)、訂閱者(subscriber)、客戶端(client)。當咱們討論Observer模式,咱們說主題(subject)和觀察者(observer)。客戶端一般是包含Main()方法的Program類。spa
1.爲何要使用事件而不是委託變量? (摘自http://kb.cnblogs.com/page/45756/)線程
using System; using System.Collections.Generic; using System.Text; // 實例:爲何使用事件而不是委託變量 namespace ConsoleApp { class Program { static void Main(string[] args) { Publishser pub = new Publishser(); Subscriber sub = new Subscriber(); pub.NumberChanged += new NumberChangedEventHandler(sub.OnNumberChanged); pub.DoSomething(); // 應該這樣觸發事件 pub.NumberChanged("使用委託"); // 可是被這樣調用了,對委託變量的恰當使用 } } // 定義委託 public delegate void NumberChangedEventHandler(string Name); // 定義事件發佈者 public class Publishser { private string Name; public NumberChangedEventHandler NumberChanged; // 聲明委託變量 //public event NumberChangedEventHandler NumberChanged; // 聲明一個事件 public void DoSomething() { // 在這裏完成一些工做 ... if (NumberChanged != null) { // 觸發事件 NumberChanged(Name); } } } // 定義事件訂閱者 public class Subscriber { public void OnNumberChanged(string Name) { Console.WriteLine("{0}已響應", Name); } } }
2.如何讓事件只容許一個客戶訂閱?(事件訪問器)指針
using System; using System.Collections.Generic; using System.Text; // 實例:讓事件只容許一個客戶訂閱 namespace ConsoleApp { class Program3 { static void Main(string[] args) { Publishser pub = new Publishser(); Subscriber1 sub1 = new Subscriber1(); Subscriber2 sub2 = new Subscriber2(); pub.NumberChanged -= sub1.OnNumberChanged; // 不會有任何反應 pub.NumberChanged += sub2.OnNumberChanged; // 註冊了sub2 pub.NumberChanged += sub1.OnNumberChanged; // sub1將sub2的覆蓋掉了 pub.DoSomething(); // 觸發事件 } } // 定義委託 public delegate string GeneralEventHandler(); // 定義事件發佈者 public class Publishser { // 聲明一個委託變量或事件都無所謂 private GeneralEventHandler numberChanged; // 事件訪問器的定義 public event GeneralEventHandler NumberChanged { add { numberChanged = value; //只容許註冊一個事件,重複註冊則替換前者 } remove { numberChanged -= value; } } public void DoSomething() { // 作某些其餘的事情 if (numberChanged != null) { // 觸發事件 string rtn = numberChanged(); Console.WriteLine("Return: {0}", rtn); // 打印返回的字符串 } } } // 定義事件訂閱者 public class Subscriber1 { public string OnNumberChanged() { Console.WriteLine("Subscriber1 Invoked!"); return "Subscriber1"; } } public class Subscriber2 { public string OnNumberChanged() { Console.WriteLine("Subscriber2 Invoked!"); return "Subscriber2"; } } }
3.處理異常和訂閱者方法超時的處理code
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Runtime.Remoting.Messaging; using System.IO; // 處理異常 namespace ConsoleApp { class Program6 { static void Main(string[] args) { Publisher pub = new Publisher(); Subscriber1 sub1 = new Subscriber1(); Subscriber2 sub2 = new Subscriber2(); Subscriber3 sub3 = new Subscriber3(); pub.MyEvent += new EventHandler(sub1.OnEvent); pub.MyEvent += new EventHandler(sub2.OnEvent); pub.MyEvent += new EventHandler(sub3.OnEvent); pub.DoSomething(); // 觸發事件 Console.WriteLine("Control back to client!\n"); // 返回控制權 Console.WriteLine("Press any thing to exit...\n"); Console.ReadKey(); // 暫停客戶程序,提供時間供訂閱者完成方法 } } public class Publisher { public event EventHandler MyEvent; public void DoSomething() { // 作某些其餘的事情 Console.WriteLine("DoSomething invoked!"); if (MyEvent != null) { Delegate[] delArray = MyEvent.GetInvocationList(); foreach (Delegate del in delArray) { EventHandler method = (EventHandler)del; method.BeginInvoke(null, EventArgs.Empty, null, null); } } } } public class Subscriber1 { public void OnEvent(object sender, EventArgs e) { Thread.Sleep(TimeSpan.FromSeconds(3)); // 模擬耗時三秒才能完成方法 Console.WriteLine("Waited for 3 seconds, subscriber1 invoked!"); } } public class Subscriber2 { public void OnEvent(object sender, EventArgs e) { throw new Exception("Subsciber2 Failed"); // 即便拋出異常也不會影響到客戶端 //Console.WriteLine("Subscriber2 immediately Invoked!"); } } public class Subscriber3 { public void OnEvent(object sender, EventArgs e) { Thread.Sleep(TimeSpan.FromSeconds(2)); // 模擬耗時兩秒才能完成方法 Console.WriteLine("Waited for 2 seconds, subscriber3 invoked!"); } } }
4.委託和方法的異步調用
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Runtime.Remoting.Messaging; namespace ConsoleApp { public delegate int AddDelegate(int x, int y); class Program9 { static void Main(string[] args) { Console.WriteLine("--------客戶端執行開始,即將調用異步"); Thread.CurrentThread.Name = "客戶端線程Name"; Calculator cal = new Calculator(); AddDelegate del = new AddDelegate(cal.Add); string data = "客戶端數據."; //異步完成後掛載的方法返回的數據 AsyncCallback callBack = new AsyncCallback(OnAddComplete); //異步完成後掛載方法 del.BeginInvoke(2, 5, callBack, data); // 異步調用方法 // 作某些其它的事情,模擬須要執行3秒鐘 for (int i = 1; i <= 3; i++) { Thread.Sleep(TimeSpan.FromSeconds(i)); Console.WriteLine("{0}: 模擬執行其餘事情 {1} 秒鐘.", Thread.CurrentThread.Name, i); } Console.WriteLine("\n-------客戶端執行完畢..."); Console.ReadKey(); } static void OnAddComplete(IAsyncResult asyncResult) { AsyncResult result = (AsyncResult)asyncResult; AddDelegate del = (AddDelegate)result.AsyncDelegate; string data = (string)asyncResult.AsyncState; int rtn = del.EndInvoke(asyncResult); Console.WriteLine("{0}: 異步返回值, {1}; Data: {2}\n", Thread.CurrentThread.Name, rtn, data); } } public class Calculator { public int Add(int x, int y) { if (Thread.CurrentThread.IsThreadPoolThread) { Thread.CurrentThread.Name = "異步線程Name"; } Console.WriteLine("--------異步開始!"); // 執行某些事情,模擬須要執行2秒鐘 for (int i = 1; i <= 2; i++) { Thread.Sleep(TimeSpan.FromSeconds(i)); Console.WriteLine("{0}: 模擬執行事情 {1} 秒鐘.", Thread.CurrentThread.Name, i); } Console.WriteLine("--------異步結束!"); return x + y; } } }
2、異常和錯誤 (try-catch-finally)
基類:System.Exception
try語句提供了一種機制來捕捉塊執行過程當中發生的異常。如下是它的三種可能的形式(s可多個catch):
●try-catch(s)
●try-finally
●try-catch(s)-finally
try{申請資源,如數據庫鏈接,網絡鏈接,打開文件等可能出現異常的代碼}
catch(異常類型 e){處理異常一類型的異常}
finally{釋放資源}
手動跑出異常:throw new System.Exception();