.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方法将事件处理方法绑定到委托链中

 

时间: 2024-10-11 16:58:10

.NET基础拾遗(4)委托和事件2的相关文章

.NET基础拾遗(4)委托、事件、反射与特性

Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 一.委托基础 1.1 简述委托的基本原理 委托这个概念对C++程序员来说并不陌生,因为它和C++中的函数指针非常类似,很多码农也喜欢称委托为安全的函数指针.无论这一说法是否正确,委托的的确确实现了和函数指针类似的功能,那就是提供了程序回调指定方法的机制. 在委托内部,包含了一个指向某个方法的指针(这一点上委托实现机制和C++的函数指针一致),为何称其

【.NET基础】--委托、事件、线程(3)

之前的两篇文章我们了解了委托和事件,本文我们看一下线程. 1,一个窗体程序,默认拥有一个线程(相当于一个商店里面,只有一个店员),这个默认的线程叫做 UI线程/主线程. 2,进程和线程的关系: A,进程,包含程序运行所需要的资源 ,在大多数情况下是指 程序.(商店:囤积要使用的资源的地方) B,线程,是在进程中能够被CPU调用的程序单元,是提供给CPU运行程序的代码片段.(商店员工:是运行程序的行动者) C,一个进程至少一个线程,每一个线程有自己专属的寄存器(栈指针.程序计数器等)但代码区是共享

C#基础加强篇—委托、Lambda表达式和事件(下)

3.事件 事件作为C#中的一种类型,为类和类的实例定义发出通知的能力,从而将事件和可执行代码捆绑在了一起.事件是对象发送的消息,以发信号通知操作的发生.操作可能是由用户交互引起的,也可能是由某些其他的程序逻辑触发的.引发(触发)事件的对象叫做事件发送方,捕获事件并对其做出响应的对象叫做事件接收方. C#事件是按“发布——预定”的方式工作.先在一个类中公布事件,然后就可以在任意数量的类中对事件预定.在事件通信中,事件发送方类并不知道哪个对象或方法将接收到(处理)它所引发的事件.所需要的是在源和接收

.NET零基础入门05:委托与事件

一:前言 本小节,我们需要停一停我们的小游戏开发,虽然它现在还不完美,还很简单,甚至还有BUG.但是,为了更好的理解C#,现在到了该深入了解一些基础知识的时候了. 当然,实际上,本小节内容对于零基础入门的初学者来说,还是有点难了.委托与事件,如果只是泛泛的说一下,可能就是一两句话.但是,我们的课程要遵循一个原则:知其然,知其所以然.所以,本小节的内容实际上有点多,但是我希望大家细细品味,争取彻底消化委托和事件这两个概念. 同时,本课程还要教会大家使用一个工具,分析代码. 二:委托的现实场景:卖家

面向对象基础(继承类,抽象方法,接口,委托和事件)

1.页面上实现猫叫,狗叫,虎叫 <asp:Button ID="cat" runat="server" Text="猫叫" onclick="cat_Click" /><br/> <asp:Button ID="dog" runat="server" Text="狗叫" onclick="dog_Click" />

【.NET基础】--委托、事件、线程(2)

本文介绍event的使用以及原理,本文接上一篇文章的Demo继续[下载上一篇Demo] 上一篇我们在类(dg_SayHi.cs)里面定义代理了4个Delegate,然后在Button的后台事件中 新建委托对象并初始化,这样去使用委托.本文我们看一下event的使用以及原理. 1,现在我们在Person类里面 定义一个dg_SayHi委托变量,这样新建person类对象后就可以操作这个委托变量 A,Person类添加委托变量 public class Person { #region 姓名 str

unity基础之C#基础——[转]大白话系列之C#委托与事件讲解(一)

从序言中,大家应该对委托和事件的重要性有点了解了吧,虽然说我们现在还是能模糊,但是从我的大白话系列中,我会把这些概念说的通俗易懂的.首先,我们还是先说说委托吧,从字面上理解,只要是中国人应该都知道这个意思,除非委托2个中文字不认识,举个例子,小明委托小张去买车票.     但是在我们的程序世界里,也是这么的简单吗?当然,什么是OO,OO就是现实世界的抽象,所有现实世界的事物,在OO里都能得到很好的诠释,不好意思,扯远了...... 那我们就单刀直入吧,如果同学们不嫌烦的话,可以看一下,网上中文,

【Unity|C#】基础篇(8)——委托(Delegate)/ 事件(Event)

[学习资料] > 在线文档 官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/ 菜鸟教程(高级教程):https://www.runoob.com/csharp/csharp-tutorial.html > 视频教程 腾讯学院.Siki学院         > 书籍 <C#图解教程>(第13~14章):https://www.cnblogs.com/moonache/p/7687551.html [学习内容] > 菜

委托与事件

委托在底层就是一个函数的指针,委托是事件的基础. 你可以传递引用类型.值类型.但是你有没有需要传一个方法呢?传方法的过程就是委托. 消息类: public class Message { /// <summary> /// 传引用类型 /// </summary> /// <param name="msg"></param> public static void Send(string msg) { Console.WriteLine(&

C#中委托和事件

目 录 1.1 理解委托 2 1.1.1 将方法作为方法的参数 2 1.1.2 将方法绑定到委托 4 1.2 事件的由来 6 1.2.1 更好的封装性 6 1.2.2 限制类型能力 9 1.3 委托的编译代码 10 1.4 .NET 框架中的委托和事件 11 1.4.1 范例说明 11 1.4.2 Observer 设计模式简介 12 1.4.3 实现范例的Observer 设计模式 13 1.4.4 .NET 框架中的委托与事件 14 1.5 委托进阶 16 1.5.1 为什么委托定义的返回值