事件提供了一种标准的机制来通知监听者。.NET的事件模式使用了事件语法来实现观察者模式。任意数量的客户对象都可以将自己的处理函数注册到事件上,然后处理这些事件。这些客户对象不需要再编译期就给出。时间也不必非要有订阅者才能正常工作。在C#中使用事件可以降低发送者和可能的通知接受者之间的耦合。发送者可以完全独立于接收者进行开发。事件是实现广播类型行为信息的标准方式。 

    下面按照使用场景的不同,简单列举三种事件模式的实现方式:

    . 公共代码部分

       /// <summary>

复制代码
/// 日志参数类
/// </summary>
public class LoggerEventArgs : EventArgs
{
public string Message { get; private set; }
public int Priority { get; private set; } public LoggerEventArgs(int p, string m)
{
Priority = p;
Message = m;
}
}
复制代码 . 最常用方式 /// <summary> 复制代码
/// 日志类(第一版):最常见的使用方法,适用于单一调用者情况。
/// </summary>
public class Logger
{
/// <summary>
/// 内部事件句柄
/// </summary>
public event EventHandler<LoggerEventArgs> Log;
/// <summary>
/// 内部日志单键实例
/// </summary>
private static Logger theOnly = null;
public static Logger Singleton
{
get { return theOnly; }
} private Logger()
{ } static Logger()
{
theOnly = new Logger();
} /// <summary>
/// 添加日志信息
/// </summary>
/// <param name="priority"></param>
/// <param name="msg"></param>
public void AddMsg(int priority, string msg)
{
// 该临时变量可预防多线程环境中的竞争条件
EventHandler<LoggerEventArgs> l = Log;
// 执行事件方法
if (l != null)
{
l(this, new LoggerEventArgs(priority, msg));
}
}
}
复制代码 . 针对事件数量多的情况 /// <summary> 复制代码
/// 日志类(第二版):适用于包含事件数量非常多的情况,即添加了一个事件容器,避免因多事件导致的设计臃肿。
/// </summary>
public sealed class Logger
{
/// <summary>
/// 事件容器
/// </summary>
private static System.ComponentModel.EventHandlerList Handlers = new System.ComponentModel.EventHandlerList(); /// <summary>
/// 添加事件
/// </summary>
/// <param name="system"></param>
/// <param name="ev"></param>
public static void AddLogger(string system, EventHandler<LoggerEventArgs> ev)
{
Handlers.AddHandler(system, ev);
} /// <summary>
/// 清除事件
/// </summary>
/// <param name="system"></param>
/// <param name="ev"></param>
public static void RemoveLogger(string system, EventHandler<LoggerEventArgs> ev)
{
Handlers.RemoveHandler(system, ev);
} /// <summary>
/// 添加日志信息
/// </summary>
/// <param name="system"></param>
/// <param name="priority"></param>
/// <param name="msg"></param>
public static void AddMsg(string system, int priority, string msg)
{
if (!string.IsNullOrEmpty(system))
{
// 根据key获取相应的事件
EventHandler<LoggerEventArgs> l = Handlers[system] as EventHandler<LoggerEventArgs>;
// 事件参数
LoggerEventArgs args = new LoggerEventArgs(priority, msg);
if (l != null)
{
l(null, args);
}
// 若不存在,执行默认事件
l = Handlers[""] as EventHandler<LoggerEventArgs>;
if (l != null)
{
l(null, args);
}
}
}
}
复制代码 . 针对事件数量多的情况(泛型版本) /// <summary> 复制代码
/// 日志类(第三版):适用于多事件情况的泛型版本。主要优势是降低了转型/转换的工作,但增加了一些用来映射事件的代码。
/// </summary>
public sealed class Logger
{
/// <summary>
/// 事件字典
/// </summary>
private static Dictionary<string, EventHandler<LoggerEventArgs>> Handlers = new Dictionary<string, EventHandler<LoggerEventArgs>>(); /// <summary>
/// 添加事件
/// </summary>
/// <param name="system"></param>
/// <param name="ev"></param>
static public void AddLogger(string system, EventHandler<LoggerEventArgs> ev)
{
if (Handlers.ContainsKey(system))
{
Handlers[system] += ev;
}
else
{
Handlers.Add(system, ev);
}
} /// <summary>
/// 清除事件
/// </summary>
/// <param name="system"></param>
/// <param name="ev"></param>
static public void RemoveLogger(string system, EventHandler<LoggerEventArgs> ev)
{
Handlers[system] -= ev;
} /// <summary>
/// 添加日志信息
/// </summary>
/// <param name="system"></param>
/// <param name="priority"></param>
/// <param name="msg"></param>
static public void AddMsg(string system, int priority, string msg)
{
if (string.IsNullOrEmpty(system))
{
// 从字典中获取事件
EventHandler<LoggerEventArgs> l = null;
Handlers.TryGetValue(system, out l);
// 事件参数
LoggerEventArgs args = new LoggerEventArgs(priority, msg);
// 执行事件
if (l != null)
{
l(null, args);
}
// 若不存在,则尝试执行默认事件
l = Handlers[""] as EventHandler<LoggerEventArgs>;
if (l != null)
{
l(null, args);
}
}
}
}
复制代码 至于选择哪种方式来实现,就要看具体的应用场景了;此外,大多数时候我们都会使用匿名委托来声明回调函数,或事件委托,所以会导致代码的运行时态有一些小波折,尤其在读别人的代码的时候,这样的情况很普遍,会不会有更好的办法来让这种回调和委托比较容易跟踪?这个还在思考中……

C#代码:用事件模式实现通知的更多相关文章

  1. OneAlert 入门(四)——事件分派和通知必达

    OneAlert 是国内首个 SaaS 模式的云告警平台,集成国内外主流监控/支撑系统,实现一个平台上集中处理所有 IT 事件,提升 IT 可靠性.有了 OneAlert,你可以更快更合理地为事件划分 ...

  2. 【转载】详细解读C#中的 .NET 弱事件模式

    你可能知道,事件处理是内存泄漏的一个常见来源,它由不再使用的对象存留产生,你也许认为它们应该已经被回收了,但不是,并有充分的理由. 在这个短文中(期望如此),我会在 .Net 框架的上下文事件处理中展 ...

  3. C#中的 .NET 弱事件模式

    引言 你可能知道,事件处理是内存泄漏的一个常见来源,它由不再使用的对象存留产生,你也许认为它们应该已经被回收了,但不是,并有充分的理由. 在这个短文中(期望如此),我会在 .Net 框架的上下文事件处 ...

  4. 在WPF中应用弱事件模式

    http://www.cnblogs.com/rickiedu/archive/2007/03/15/676021.html 在wpf中应用弱事件模式        感谢VS 的Intellisens ...

  5. WPF程序中的弱事件模式

    在C#中,得益于强大的GC机制,使得我们开发程序变得非常简单,很多时候我们只需要管使用,而并不需要关心什么时候释放资源.但是,GC有的时并不是按照我们所期望的方式工作. 例如,我想实现一个在窗口的标题 ...

  6. Java小知识----POI事件模式读取Excel 2007

    一.知识背景 1.读取excel的方法选择问题 java中读excel中的时间,我们通常用POI去解析,在使用new HSSFWorkbook(NEW FileInputStream(excelFil ...

  7. 从B站的代码泄露事件中,我们能学到些什么?

    先声明一下,本文不聊ISSUE中的七七八八,也不聊代码是否写的好,更不聊是不是跟蔡徐坤有关之类的吃瓜内容.仅站在技术人的角度,从这次的代码泄露事件,聊聊在代码的安全管理上,通常都需要做哪些事来预防此类 ...

  8. 190行代码实现mvvm模式

    前言 网上讲 vue 原理,mvvm 模式的实现,数据双向绑定的文章一搜一大堆,不管写的谁好谁坏,都是写的自己的理解,我也发一篇文章记录自己的理解,如果对看官有帮助,那也是我莫大的荣幸,不过看完之后, ...

  9. C# 标准事件模式

    .NET框架为事件定义了一个标准模式,它的目的是保持框架和用户代码之间的一致性. 标准事件的模式核心是SystemEventArgs——预定义的没有成员的框架类(不同于静态Empty属性) Event ...

随机推荐

  1. sphinx 全配置

    ## 数据源src1 source src1 { ## 说明数据源的类型.数据源的类型可以是:mysql,pgsql,mssql,xmlpipe,odbc,python ## 有人会奇怪,python ...

  2. BZOJ 2393 Cirno的完美算数教室

    就是爆搜嘛. 先从大到小排个序能减去dfs树上很大的一部分.这个技巧要掌握. #include<iostream> #include<cstdio> #include<c ...

  3. HTML中的鼠标光标属性

    在网页中默认的鼠标指针只有两种,一种是最普通的箭头,另一种是当移动到链接上时出现的“小手”.但现在越来越多的网页都使用了CSS鼠标指针技术,当将鼠标移动到链接上时,可以看到多种不同的效果.CSS可以通 ...

  4. PDOStatement::bindParam的一个陷阱

    废话不多说, 直接看代码: <?php $dbh = new PDO('mysql:host=localhost;dbname=test', "test"); $query ...

  5. Inno如何在安装完成时删除指定的文件夹(下的所有文件及子目录)??

    删除安装目录下的任意文件夹及下的所有文件及子目录,或者删除指定目录的文件夹,要如何做到呢?谢谢!! //删除文件    用 DeleteFile 只能删除一个文件,不能使用通配符来删除多个文件Dele ...

  6. C#实现union以及lock的使用

    1.什么是Union类型数据 联合(Union)是一种特殊的类,一个联合中的数据成员在内存中的存储是互相重叠的.每个数据成员都在相同的内存地址开始. 分配给联合的存储区数量是“要包含它最大的数据成员” ...

  7. 纯 CSS 创建一个三角形

    [要求]:用纯CSS创建一个三角形的原理是什么? ♪ 答: 把上.左.右三条边隐藏掉(颜色设为 transparent) [实现]: #demo { width: 0; height: 0; bord ...

  8. tcpdump抓包规则命令大全

    下面的例子全是以抓取eth0接口为例,如果不加”-i eth0”是表示抓取所有的接口包括lo. 1.抓取包含10.10.10.122的数据包 # tcpdump -i eth0 -vnn host 1 ...

  9. Ubuntu14.04安装配置Open vSwitch

    最近在研究学习Open vSwitch,准备在本地Ubuntu14.04机器上安装一下,并基于其创建一些KVM虚拟机,下面就简要记录下在Ubuntu14.04系统上安装Open vSwitch的过程. ...

  10. log4j 分类输出

    一个log4j的问题也是折磨了我两天了. 终于算是实现了个符合需求的小demo.然而,我必须吧log4j搞定,这个乐塞. 需求描述: 用xml配置文件,将debug.info.warn.error分类 ...