using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApplication5
{
public sealed class EventKey { }
public sealed class EventSet
{
//内部管理一个事件的字典,key为每次生成的所以哈希码是不同的,以确认字典的键不会重复
private readonly Dictionary<EventKey, Delegate> m_events = new Dictionary<EventKey, Delegate>();
/// <summary>
/// Monitor.Enter线程安全,在指定对象上获取排它锁
/// </summary>
/// <param name="eventKey"></param>
/// <param name="handle"></param>
public void Add(EventKey eventKey,Delegate handle)
{
//获取指定对象上的排它锁,线程安全,确保我在增加一个键值对的时候不会发生导致线程不安全的情况
Monitor.Enter(m_events);
Delegate d;
//获取指定键相关联的值,关键是这样可以防止字典的键不存在时,还要写代码去判断键是否存在的情况
m_events.TryGetValue(eventKey, out d);
//将两个委托的调用列表链接在一起
m_events[eventKey] = Delegate.Combine(d, handle);
//释放指定对象上的排它锁
Monitor.Exit(m_events); }
public void Remove(EventKey eventKey, Delegate handler)
{
Monitor.Enter(m_events);
Delegate d;
if (m_events.TryGetValue(eventKey, out d))
{
//从指定的源上删除某个委托,内部执行多路广播委托,删除后委托链的头部地址会改变
d = Delegate.Remove(d, handler); //删除后还有委托,设置新的头部地址
if (d != null)
{
m_events[eventKey] = d;
}
else
{
m_events.Remove(eventKey);
}
Monitor.Exit(m_events); }
}
//激发事件委托
public void Raise(EventKey eventKey, Object sender, EventArgs e)
{
Delegate d;
Monitor.Enter(m_events);
m_events.TryGetValue(eventKey,out d);
Monitor.Exit(m_events);
if (d != null)
{
d.DynamicInvoke(new object[] {sender,e });
}
} }
public class FooEventArgs : EventArgs { }
public class TypeWithLotsOfEvents
{ private readonly EventSet m_eventSet = new EventSet();
protected EventSet EventSet { get { return m_eventSet; } }
//对于TypeWithLotsOfEvents的每个实例对应的 下列字段key是唯一的
protected static readonly EventKey s_fooEventKey = new EventKey(); public event EventHandler<FooEventArgs> FOO
{
add { m_eventSet.Add(s_fooEventKey, value); }
remove { m_eventSet.Remove(s_fooEventKey, value); }
} protected virtual void OnFOO(FooEventArgs e)
{
m_eventSet.Raise(s_fooEventKey, this, e);
}
public void SimulateFOO()
{
OnFOO(new FooEventArgs());
} }
class Program
{
static void Main(string[] args)
{
TypeWithLotsOfEvents twle = new TypeWithLotsOfEvents();
twle.FOO += Twle_FOO;
twle.SimulateFOO();
Console.ReadKey(); } private static void Twle_FOO(object sender, FooEventArgs e)
{
Console.WriteLine("Hading Foo Event here...");
}
}
}

CLR 显示实现事件 EventSet内部管理一个字典的更多相关文章

  1. [转]3天搞定的小型B/S内部管理类软件定制开发项目【软件开发实战10步骤详解】

    本文转自:http://www.cnblogs.com/jirigala/archive/2010/10/07/1845275.html 2010-10-07 21:39 by 通用C#系统架构, 5 ...

  2. 关于vue事件监听的一个问题

    由于新工作需要用vue,所以最近接触最多的也是vue,因为之前一直在用react,所以对于vue上手还是很快的.我也尽量找一些他们两个的异同点,除了多了一些辅助用的方法以外,最大的不同应该是对于组件间 ...

  3. [CLR via C#]21. 自动内存管理(垃圾回收机制)

    目录 理解垃圾回收平台的基本工作原理 垃圾回收算法 垃圾回收与调试 使用终结操作来释放本地资源 对托管资源使用终结操作 是什么导致Finalize方法被调用 终结操作揭秘 Dispose模式:强制对象 ...

  4. Android软键盘的隐藏显示、事件监听的代码

    把开发过程中重要的一些内容片段做个珍藏,如下资料是关于Android软键盘的隐藏显示.事件监听的内容,应该是对小伙伴们有所用途. public class ResizeLayout extends L ...

  5. CLR VIA C#事件

    事件是类型的一个成员,用来在事情发生的时候通知注册了该事件的成员. 事件和观察者模式十分的相似,所以事件应该提供如下几种能力 1.能让对象的方法登记对他的关注 2.能让对象的方法取消对他的关注 3.能 ...

  6. js闭包(函数内部嵌套一个匿名函数:这个匿名函数可将所在函数的局部变量常驻内存)

    js闭包(函数内部嵌套一个匿名函数:这个匿名函数可将所在函数的局部变量常驻内存) 一.总结 1.闭包:就是在一个函数内部嵌套一个匿名函数,这个匿名函数可以访问这个函数的变量. 二.要点 闭包 闭包的相 ...

  7. 一个字典通过dictionaryWithDictionary 他们的内存指针是不同的

    一个字典通过dictionaryWithDictionary 他们的内存指针是不同的  来自为知笔记(Wiz)

  8. 有一个字典对象,d = {'a':1,'b':2},请用尽量简洁的代码将d转换成{1: 'a', 2: 'b'}

    题目:有一个字典对象,d = {'a':1,'b':2},请用尽量简洁的代码将d转换成{1: 'a', 2: 'b'} 第一种方法: d = {'a': 1, 'b': 2}d = {value: k ...

  9. Python把两个列表合成一个字典

    简单粗暴上代码 A= [] B = [] C= dict(map(lambda x,y:[x,y],A,B)) 酱紫,就合成了一个字典

随机推荐

  1. SCARA——OpenGL入门学习四(颜色)

    OpenGL入门学习[四] 本次学习的是颜色的选择.终于要走出黑白的世界了~~ OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. 无论哪种颜色模式,计算机都必须为每一个像素保存一些数 ...

  2. JsQuick--个人封装的Js库

    JsQuick 该库为本人封装的Js库,尚未进行浏览器兼容 /** * 快速框架 版本:1.0.0 * 日期:2015.02.26 * 作者:简楚恩 */ /** * 快速获取控件类 */ var $ ...

  3. HttpContext.Current.Cache和HttpRuntime.Cache的区别,以及System.Runtime.Caching

    先看MSDN上的解释:      HttpContext.Current.Cache:为当前 HTTP 请求获取Cache对象.      HttpRuntime.Cache:获取当前应用程序的Cac ...

  4. C# 实现程序只启动一次(总结)

    我前面的三篇文章是从网上找到的(如下链接),都说是实现程序只启动一次的功能. C#防止程序多次运行C#检测程序重复运行的函数(可以在多用户登录情况下检测)C# 实现程序只启动一次(多次运行激活第一个实 ...

  5. Visual Studio Code教程:基础使用和自定义设置

    一.界面介绍 1.1 界面介绍 1.2 文件夹和文件的打开 文件——>打开文件夹/打开文件 1.3 新建文件/文件夹 新建文件: a. 文件——>新建文件: b. 按Ctrl+n; c. ...

  6. 获取设备 ID 和名称

    获取设备 ID 和名称 .NET Framework 3.5   其他版本   更新:2007 年 11 月 要获取设备的名称,请使用 Dns.GetHostName 属性.通常情况下,默认名称为“P ...

  7. cowboy的例子

    大体参考的这里,非常感谢他的例子 开发的时候先下载好cowboy的库,放到~/.erlang里面 code:add_pathz("/Users/mmc/erlang/3rd_libs/cow ...

  8. 如何在已经安装好的Nginx上增加新模块

    学习资源: https://blog.csdn.net/dxm2025/article/details/41149865 https://blog.csdn.net/qq_36663951/artic ...

  9. FPGA前世今生(三)

    上期介绍了关于FPGA的IOB单元,这期我们介绍一下FPGA内部的其他资源,这些都是学好FPGA的基础.不管前世的沧桑,还是后世的风光,我们都要把我现在的时光,打好基础,学好FPGA. 大多数FPGA ...

  10. java从键盘输入打印出直角三角形

    package com.aaa; import java.util.Scanner; //重在参与,欢迎评价,吐槽~~~~//输出直角三角形 public class Se { public stat ...