.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方法将事件处理方法绑定到委托链中。
.NET基础拾遗(4)委托和事件2的更多相关文章
- C#基础篇 - 理解委托和事件
1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托是C#中类型安全的,可以订阅一个或多个具有相同签名方法的函数指针.简单理解,委托是一种可以把函数当做参数传递的类型.很多情况下,某 ...
- C# 篇基础知识5——委托和事件
事件处理程序是基于“委托”机制运行的. 1.委托 (1)委托的定义和使用 有时需要将一个函数作为另一个函数的参数,这时就要用到委托(Delegate)机制.例如设计一个马戏表演函数: //定义委托 d ...
- .NET基础拾遗(4)委托、事件、反射与特性
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- 【.NET基础】--委托、事件、线程(3)
之前的两篇文章我们了解了委托和事件,本文我们看一下线程. 1,一个窗体程序,默认拥有一个线程(相当于一个商店里面,只有一个店员),这个默认的线程叫做 UI线程/主线程. 2,进程和线程的关系: A,进 ...
- 转载 【.NET基础】--委托、事件、线程(3)
之前的两篇文章我们了解了委托和事件,本文我们看一下线程. 1,一个窗体程序,默认拥有一个线程(相当于一个商店里面,只有一个店员),这个默认的线程叫做 UI线程/主线程. 2,进程和线程的关系: A ...
- 转载 【.NET基础】--委托、事件、线程(2) https://www.cnblogs.com/chengzish/p/4569912.html
[.NET基础]--委托.事件.线程(2) 本文介绍event的使用以及原理,本文接上一篇文章的Demo继续[下载上一篇Demo] 上一篇我们在类(dg_SayHi.cs)里面定义代理了4个Del ...
- 转载 【.NET基础】--委托、事件、线程(1) https://www.cnblogs.com/chengzish/p/4559268.html
[.NET基础]--委托.事件.线程(1) 1,委托 是存放方法的指针的清单,也就是装方法的容器 A, 新建winform项目[01委托],项目中添加dg_SayHi.cs 委托类 用于存储方法 ...
- .NET零基础入门05:委托与事件
一:前言 本小节,我们需要停一停我们的小游戏开发,虽然它现在还不完美,还很简单,甚至还有BUG.但是,为了更好的理解C#,现在到了该深入了解一些基础知识的时候了. 当然,实际上,本小节内容对于零基础入 ...
- C#基础加强篇—委托、Lambda表达式和事件(下)
3.事件 事件作为C#中的一种类型,为类和类的实例定义发出通知的能力,从而将事件和可执行代码捆绑在了一起.事件是对象发送的消息,以发信号通知操作的发生.操作可能是由用户交互引起的,也可能是由某些其他的 ...
- .NET C#基础(3):事件 - 不便处理的事就委托出去
0. 文章目的 本文面向有一定.NET C#基础知识的学习者,介绍.NET中事件的相关概念.基本知识及其使用方法 1. 阅读基础 理解C#基本语法(方法的声明.方法的调用.类的定义) 2. 从 ...
随机推荐
- django: form fileupload - 2
继续介绍文件上传的第二种形式和第三种形式. ------------------------------------------------------------- 第二种形式较简单,直接用 DB ...
- 使用Razor来进行页面布局
UI设计师们现在也讲究页面设计的语义化和结构化,把一个页面分成很多个模块,使用语义化的类名或id来标识这些模块.Razor推出了新的布局解决方案来迎合这一潮流. 这里涉及到Razor的一些语法,大家可 ...
- Redhat修改本地yum源
1.将Centos系统的ios文件传到服务器,比如传到/root目录下: 2.将ios文件挂载到本地,需要在本地建立一个文件夹,比如/yum; mkdir /yum mount -o loop /ro ...
- Swift中对计算属性的理解和对之前的补充
这个功能的重点作用应该是在计算上. 对于一般的属性,要么直接存一个,要么直接读一个,计算属性则可以根据所设置内容,进行一些修改或计算之类的, 比如: import UIKit class sample ...
- Asp.Net--上传大文件(页面超时)
几个方法: 修改文件上传大小的限制 以文件形式保存到服务器 转换成二进制字节流保存到数据库 将二进制通过循环的方式写入磁盘 一.修改文件上传大小的限制 通过对web.config和machine.co ...
- xml bug
在Eclipse 创建动态WEB 工程,在src 下 创建 config.xml: 1 <?xml version="1.0" encoding="UTF-8&qu ...
- kafka安装及Kafka-PHP扩展的使用
话说用了就要有点产出,要不然过段时间又忘了,所以在这里就记录一下试用Kafka的安装过程和php扩展的试用. 实话说,如果用于队列的话,跟PHP比较配的,还是Redis.用的顺手,呵呵,只是Redis ...
- 个性A标签
问题: 前段时间,小琳同学问我A标签为啥alert出来的是它的href? 示例: 先来两个标签比较一下. <a id="a" href="http://www.ba ...
- (转载)MVC 4.0 PartialView()与View()真的一样吗?
转载自:http://www.cnblogs.com/lori/ 当我们使用razor作为页面引擎时,它的视图文件扩展名为cshtml或者vbshtml,而之前作为分部视图的ascx文件,进行razo ...
- C语言基础学习学习前的准备-1
C语言概述 欢迎来到C的世界!C语言之所以命名为C,是因为C语言源自Ken Thompson发明的B语言.它是一种可移植语言,通常一个C程序可以经过很少的改动甚至不经改动就可以在其它系统上运行:它强大 ...