方案二: 永不为空, 默认加载一个订阅者
我们面临的主要问题是有可能委托为空. 那么如果事先加载一个委托,会怎么样?
public class EmptySubscriberMessenger : IMessenger{
// 立刻给它一个空的订阅者
public event EventHandler<MessageReceivedEventArgs> MessageReceived = (s, e) => { };
// 现在根本无需检查是否为 null!
public void OnNewMessage(string message)
{
MessageReceived(this, new MessageReceivedEventArgs(message));
}
}
// 立刻给它一个空的订阅者
public event EventHandler<MessageReceivedEventArgs> MessageReceived = (s, e) => { };
// 现在根本无需检查是否为 null!
public void OnNewMessage(string message)
{
MessageReceived(this, new MessageReceivedEventArgs(message));
}
}
方案三: 创建一个本地的委托副本
另外一个简单的方案, 也就是很多人都在使用的, 微软建议的模式: 创建一个本地的委托副本.
public class LocalCopyMessenger : IMessenger{
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
// 当我们引发事件时, 做一个副本
public void OnNewMessage(string message) {
var target = MessageReceived;
if (target != null)
{
target(this, new MessageReceivedEventArgs(message));
}
}
}
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
// 当我们引发事件时, 做一个副本
public void OnNewMessage(string message) {
var target = MessageReceived;
if (target != null)
{
target(this, new MessageReceivedEventArgs(message));
}
}
}
下面是以上四种方法的效率, 在执行10亿次的重复操作时:
小结
有一种编程方式叫 Cargo Cult Programming, 中文名: 货物崇拜编程. 维基定义为"
其特征为不明就里地仪式性地使用代码或程序架构。货物崇拜编程通常是一个程序员既没理解他要解决的 bug,也没理解表面上的解决方案的典型表现。
这个名词有时也指不熟练的或没经验的程序员从某处拷贝代码到另一处,却不太清楚其代码是如何工作的,或者不清楚在新的地方是否需要这段代码。也可以指不正确或过份的应用设计模式,代码风格或编程方法,却对其原理不明就里。"
我承认在"高举实用主义"(敝人的如何做一个快乐的ASP.NET程序员) 的年代, 为了效率, 我也经常这样做.--试问谁有时间给第三方控件做测试?
自从这个创建本地委托副本的方案被大牛们推荐后, 大家都在用, 有人也不一定明白它背后的故事.
有时间的朋友们聊聊.net中的野史, 谈笑间扩充一点编程的能力,总归是很有益处的。
原文阅读:C#/.NET Fundamentals: Safely and Efficiently Raising Events