在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
转自:http://www.cnblogs.com/multiplesoftware/archive/2011/12/21/2295386.html,原文名:非常好玩的C#/.NET 基础 -- 安全有效引发事件 最近在网上看到一篇很好的文章, 讨论如何安全有效的引发事件. 也许你不一定要用到下面相同的解决方案, 但是至少你应该知道在引发事件时候需要考虑的问题. 引发事件的问题引发事件是一个非常容易的事情, 但是的确也有它的误区. 让我们举个例子. 假设我们写个消息接收器, 每当我们收到一个新消息, 我们引发一个包含了新消息的事件 MessageReceived. 安装我们通常的方法,就是: public class MessageReceivedEventArgs : EventArgs 接下来, 我们创建一个非线程安全访问的类UnsafeMessenger来实现这个消息同时通知所有的订阅者(subscriber). public class UnsafeMessenger 注意, 通常OnNewMessage() 是私有的, 但是在这里为了测试的方便,我们将它设为public.
大功告成!! 是吗? 事实上, 如果我们是单线程的程序, 这的确已经足够, 但是这是非线程安全访问(thread-safe). 为什么? 想想, 订阅者可以任何时候订阅或者取消订阅. 比如,我们当前有一个订阅者, 那么当接收到一个新消息,执行到这一句时: if (MessageReceived != null) 肯定会通过, 因为有一个订阅者, 如果这个时候, 这名订阅者执行了取消订阅的命令: myMessenger.MessageReceived -= MyMessageHandler; 那么MessageReceived委托 就为null 了,
这个时候, 就会引发NullReferenceException.
方案一: 锁住它, 锁机制当允许多线程的时候, 我们可以用锁机制来避免一个用户在我们执行事件时订阅或者取消订阅, 或者在用户执行操作时, 不能引发事件.
这样, 如果有人试图订阅或取消订阅时, 必须要等待OnNewMessage事件的完成, 反之亦然.
方案二: 永不为空, 默认加载一个订阅者我们面临的主要问题是有可能委托为空. 那么如果事先加载一个委托,会怎么样?
方案三: 创建一个本地的委托副本另外一个简单的方案, 也就是很多人都在使用的, 微软建议的模式: 创建一个本地的委托副本.
下面是以上四种方法的效率, 在执行10亿次的重复操作时: 以上参考翻译自: C#/.NET Fundamentals: Safely and Efficiently Raising Events 小结有一种编程方式叫 Cargo Cult Programming, 中文名: 货物崇拜编程. 维基定义为" 其特征为不明就里地仪式性地使用代码或程序架构。货物崇拜编程通常是一个程序员既没理解他要解决的 bug,也没理解表面上的解决方案的典型表现。 这个名词有时也指不熟练的或没经验的程序员从某处拷贝代码到另一处,却不太清楚其代码是如何工作的,或者不清楚在新的地方是否需要这段代码。也可以指不正确或过份的应用设计模式,代码风格或编程方法,却对其原理不明就里。" 我承认在"高举实用主义"(敝人的如何做一个快乐的ASP.NET程序员) 的年代, 为了效率, 我也经常这样做.--试问谁有时间给第三方控件做测试? 自从这个创建本地委托副本的方案被大牛们推荐后, 大家都在用, 有人也不一定明白它背后的故事. 有时间的朋友们聊聊.net中的野史, 谈笑间扩充一点编程的能力,总比聊哪个明星又被潜规则了要有益处. 哈哈~~~ |
请发表评论