• 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();

     

  • 相关阅读:
    Vim
    CMake学习之路
    linux tree命令以树形结构显示文件目录结构
    代码阅读软件Understand安装
    ROS学习之ShadowRepository
    WPF初学(一)——布局【良好界面的基础】
    浅学JSON——Json.NET之首次试手
    JSON资料汇总
    自定义视图 视图控制器(UIViewController)
    UIView Subclass(UI,UIButton,UITextField,UILabel)
  • 原文地址:https://www.cnblogs.com/wenmaoyu/p/3159808.html
Copyright © 2020-2023  润新知