3.0 面向對象 委託和事件 異常和錯誤

1、委託和事件

  委託和事件這兩個概念是徹底配合的。委託僅僅是函數指針,那就是說,它可以引用函數,經過傳遞地址的機制完成。委託是一個類,當你對它實例化時,要提供一個引用函數,將其做爲它構造函數的參數。事件則是委託的一種表現形式。數據庫

  委託的聲明:[修飾符] delegate 返回類型 委託名(參數列表);  網絡

    簡單的委託異步

View Code
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

View Code
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

View Code
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/)線程

View Code
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.如何讓事件只容許一個客戶訂閱?(事件訪問器)指針

View Code
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

View 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.委託和方法的異步調用

View Code
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();

相關文章
相關標籤/搜索