事件

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

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

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

.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的更多相关文章

  1. C#基础篇 - 理解委托和事件

    1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托是C#中类型安全的,可以订阅一个或多个具有相同签名方法的函数指针.简单理解,委托是一种可以把函数当做参数传递的类型.很多情况下,某 ...

  2. C# 篇基础知识5——委托和事件

    事件处理程序是基于“委托”机制运行的. 1.委托 (1)委托的定义和使用 有时需要将一个函数作为另一个函数的参数,这时就要用到委托(Delegate)机制.例如设计一个马戏表演函数: //定义委托 d ...

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

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

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

    之前的两篇文章我们了解了委托和事件,本文我们看一下线程. 1,一个窗体程序,默认拥有一个线程(相当于一个商店里面,只有一个店员),这个默认的线程叫做 UI线程/主线程. 2,进程和线程的关系: A,进 ...

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

      之前的两篇文章我们了解了委托和事件,本文我们看一下线程. 1,一个窗体程序,默认拥有一个线程(相当于一个商店里面,只有一个店员),这个默认的线程叫做 UI线程/主线程. 2,进程和线程的关系: A ...

  6. 转载 【.NET基础】--委托、事件、线程(2) https://www.cnblogs.com/chengzish/p/4569912.html

    [.NET基础]--委托.事件.线程(2)   本文介绍event的使用以及原理,本文接上一篇文章的Demo继续[下载上一篇Demo] 上一篇我们在类(dg_SayHi.cs)里面定义代理了4个Del ...

  7. 转载 【.NET基础】--委托、事件、线程(1) https://www.cnblogs.com/chengzish/p/4559268.html

    [.NET基础]--委托.事件.线程(1)   1,委托 是存放方法的指针的清单,也就是装方法的容器 A, 新建winform项目[01委托],项目中添加dg_SayHi.cs 委托类 用于存储方法 ...

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

    一:前言 本小节,我们需要停一停我们的小游戏开发,虽然它现在还不完美,还很简单,甚至还有BUG.但是,为了更好的理解C#,现在到了该深入了解一些基础知识的时候了. 当然,实际上,本小节内容对于零基础入 ...

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

    3.事件 事件作为C#中的一种类型,为类和类的实例定义发出通知的能力,从而将事件和可执行代码捆绑在了一起.事件是对象发送的消息,以发信号通知操作的发生.操作可能是由用户交互引起的,也可能是由某些其他的 ...

  10. .NET C#基础(3):事件 - 不便处理的事就委托出去

    0. 文章目的   本文面向有一定.NET C#基础知识的学习者,介绍.NET中事件的相关概念.基本知识及其使用方法 1. 阅读基础   理解C#基本语法(方法的声明.方法的调用.类的定义) 2. 从 ...

随机推荐

  1. 图形绘制 Canvas Paint Path 详解

    图形绘制简介        Android中使用图形处理引擎,2D部分是android SDK内部自己提供,3D部分是用Open GL ES 1.0.大部分2D使用的api都在android.grap ...

  2. 详细介绍ASP.NET页面重定向方法

    ASP.NET中页面重定向的使用的很频繁,实现方法也有不同,自己也试过几种,现在总结一下. 一.Transfer Execute Redirect重定向方法介绍 1.Server.Transfer方法 ...

  3. 找两个string[ ]里不同的元素

    方法 1:string[] strListOne = new string[] {"Type", "Parent Id","Status"} ...

  4. MYSQL存储过程注释位置

    MYSQL数据库存储过程,像"#“和”/%%/“注释需要写在BEGIN,END语句块里面,否则保存不了,例如: CREATE PROCEDURE HelloWorld() BEGIN #大家 ...

  5. foreach遍历扩展(二)

    一.前言 假设存在一个数组,其遍历模式是根据索引进行遍历的:又假设存在一个HashTable,其遍历模式是根据键值进行遍历的:无论哪种集合,如果它们的遍历没有一个共同的接口,那么在客户端进行调用的时候 ...

  6. uCgui和emWin的区别

              在国内做嵌入式系统的,开始入门OS的时候,大家应该都会选择uC/OS,为什么?因为代码开源且资料众多嘛.由于uC/OS的原因大家也一定接触了uC/GUI的嵌入式图形软件库.其实uC ...

  7. ZOJ3551 Bloodsucker(概率dp)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Bloodsucker Time Limit: 2 Seconds      Me ...

  8. CentOS 7 之安装篇

    程序员是一个学到老的行业,因为新换一个公司,感觉也轻松了好多,自己想想还是多学一些知识吧,中国政府都要强制以每年15%的比例使用国产系统,相信Linux还是有必要学习的.因为曾经在文思做Expedia ...

  9. h5connect.js 腾讯云视频点播使用指南

    http://video.qcloud.com/download/docs/QVOD_Player_Web_SDK_Developer_Guide.pdf 腾讯云视频点播服务 Web播放器SDK开发指 ...

  10. angular-route 里面templeteUrl 动态加载

    https://segmentfault.com/q/1010000002524964