3.0 面向对象 委托和事件 异常和错误

一、委托和事件

  委托和事件这两个概念是完全配合的。委托仅仅是函数指针,那就是说,它能够引用函数,通过传递地址的机制完成。委托是一个类,当你对它实例化时,要提供一个引用函数,将其作为它构造函数的参数。事件则是委托的一种表现形式。

  委托的声明:[修饰符] 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;
        }
    }
}

    泛型委托

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;
        }
    }
}

    委托的回调方法

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类。

     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.处理异常和订阅者方法超时的处理

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!
");    // 返回控制权
            Console.WriteLine("Press any thing to exit...
");
            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("
-------客户端执行完毕...");
            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}
",
                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;
        }
    }
}

 二、异常和错误 (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();

 

原文地址:https://www.cnblogs.com/wenmaoyu/p/3159808.html