zoukankan      html  css  js  c++  java
  • .NET基础拾遗(4)委托和事件2

    事件

    事件是对象发送的消息,以发信号通知操作的发生。操作可能是由用户交互(例如鼠标单击)引起的,也可能是由某些其他的程序逻辑触发的。

    引发事件的对象称为事件发送方。捕获事件并对其作出响应的对象叫做事件接收方。

     在事件通信中,事件发送方类不知道哪个对象或方法将接收到(处理)它引发的事件。所需要的是在源和接收方之间存在一个媒介(或类似指针的机制)。

    .NET Framework 定义了一个特殊的类型(Delegate),该类型提供函数指针的功能。

    Microsoft的产品文档定义的事件:事件是一种使对象或类能够提供通知的成员

    public class ConsoleEventArgs : EventArgs
        {
            // 控制台输出的消息
            private string message;
    
            public string Message
            {
                get
                {
                    return message;
                }
            }
    
            public ConsoleEventArgs()
                : base()
            {
                this.message = string.Empty;
            }
    
            public ConsoleEventArgs(string message)
                : base()
            {
                this.message = message;
            }
        }
    
    
    /// <summary>
        /// 管理控制台,在输出前发送输出事件
        /// </summary>
        public class ConsoleManager
        {
            // 定义控制台事件成员对象
            public event EventHandler<ConsoleEventArgs> ConsoleEvent;
    
            /// <summary>
            /// 控制台输出
            /// </summary>
            public void ConsoleOutput(string message)
            {
                // 发送事件
                ConsoleEventArgs args = new ConsoleEventArgs(message);
                SendConsoleEvent(args);
                // 输出消息
                Console.WriteLine(message);
            }
    
            /// <summary>
            /// 负责发送事件
            /// </summary>
            /// <param name="args">事件的参数</param>
            protected virtual void SendConsoleEvent(ConsoleEventArgs args)
            {
                // 定义一个临时的引用变量,确保多线程访问时不会发生问题
                EventHandler<ConsoleEventArgs> temp = ConsoleEvent;
                if (temp != null)
                {
                    temp(this, args);
                }
            }
        }
    
    /// <summary>
        /// 日志类型,负责订阅控制台输出事件
        /// </summary>
        public class Log
        {
            // 日志文件
            private const string logFile = @"C:TestLog.txt";
    
            public Log(ConsoleManager cm)
            {
                // 订阅控制台输出事件
                cm.ConsoleEvent += this.WriteLog;
            }
    
            /// <summary>
            /// 事件处理方法,注意参数固定模式
            /// </summary>
            /// <param name="sender">事件的发送者</param>
            /// <param name="args">事件的参数</param>
            private void WriteLog(object sender, EventArgs args)
            {
                // 文件不存在的话则创建新文件
                if (!File.Exists(logFile))
                {
                    using (FileStream fs = File.Create(logFile)) { }
                }
    
                FileInfo fi = new FileInfo(logFile);
    
                using (StreamWriter sw = fi.AppendText())
                {
                    ConsoleEventArgs cea = args as ConsoleEventArgs;
                    sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "|" + sender.ToString() + "|" + cea.Message);
                }
            }
        }
    
    class Program
        {
            static void Main(string[] args)
            {
                // 控制台事件管理者
                ConsoleManager cm = new ConsoleManager();
                // 控制台事件订阅者
                Log log = new Log(cm);
    
                cm.ConsoleOutput("测试控制台输出事件");
                cm.ConsoleOutput("测试控制台输出事件");
                cm.ConsoleOutput("测试控制台输出事件");
    
                Console.ReadKey();
            }
        }
    

      

     事件和委托有神马联系?

    经常听人说,委托本质是一个类型,而事件本质是一个特殊的委托类型的实例。最好的办法莫过于通过查看原代码和编译后的IL代码进行分析。

      ① 回顾刚刚的代码,在ConsoleManager类中定义了一个事件成员

    public event EventHandler<ConsoleEventArgs> ConsoleEvent;

      EventHandler是.NET框架中提供的一种标准的事件模式.

      ② 下面通过Reflector来查看一下事件ConsoleEvent的IL代码(中间代码),可以更方便地看到这一点:

      首先,查看EventHandler的IL代码,可以看到在C#编译器编译delegate代码时,编译后是成为了一个class。

      其次当C#编译器编译event代码时首先为类型添加一个EventHandler<T>的委托实例对象,然后为其增加一对add/remove方法用来实现从委托链中添加和移除方法的功能。

      通过查看add_ConsoleEvent的IL代码,可以清楚地看到订阅事件的本质是调用Delegate的Combine方法将事件处理方法绑定到委托链中

     

  • 相关阅读:
    SQL SERVER 表分区测试备忘
    理解信息系统中的流程与工序
    获取最后插入的id另外方法
    asp.net 项目在 IE 11 下出现 “__doPostBack”未定义 的解决办法
    定制应用Repeater 、ListView的模版
    JavaScript学习笔记——简单无缝循环滚动展示图片的实现
    JavaScript学习笔记——JS中的变量复制、参数传递和作用域链
    CSS学习笔记——定位position属性的学习
    CSS学习笔记——CSS中定位的浮动float
    CSS学习笔记——盒模型,块级元素和行内元素的区别和特性
  • 原文地址:https://www.cnblogs.com/tiantianle/p/5734536.html
Copyright © 2011-2022 走看看