我有一个静态泛型类,它可以帮助我以极少的开销来移动事件:
public static class MessageBus<T> where T : EventArgs
{
public static event EventHandler<T> MessageReceived;
public static void SendMessage(object sender, T message)
{
if (MessageReceived != null)
MessageReceived(sender, message);
}
}
要创建系统范围的消息总线,我只需要定义一个EventArgs类来传递任意信息:
class MyEventArgs : EventArgs
{
public string Message { get; set; }
}
我对这个事件感兴趣的任何地方,我只是连接一个处理程序:
MessageBus<MyEventArgs>.MessageReceived += (s,e) => DoSomething();
同样,触发事件同样容易:
MessageBus<MyEventArgs>.SendMessage(this, new MyEventArgs() {Message="hi mom"});
使用MessageBus和自定义EventArgs类,我可以为特定类型的消息提供应用程序范围的消息接收器。当您有多个表单时,例如显示客户信息以及可能更新该信息的几个表单,这会派上用场。这些形式都没有相互了解,也没有一个需要连接到静态的“超类”。
我有几个问题:
fxCop抱怨使用静态方法和泛型,但这正是我在这里所追求的。我希望每个处理的消息类型都有一个MessageBus。使用带有泛型的静态可以使我免于编写维护MessageBus对象列表的所有代码。
是否通过MessageReceived事件将侦听对象保持为“活动”状态?
例如,也许我在Form.Load事件中有这个代码:
MessageBus<CustomerChangedEventArgs>.MessageReceived += (s,e) => DoReload();
当Form关闭时,Form是否保留在内存中,因为MessageReceived具有对其DoReload方法的引用?我应该在表单关闭时删除引用:
MessageBus<CustomerChangedEventArgs>.MessageReceived -= (s,e) => DoReload();
答案 0 :(得分:3)
嗯,是的,你应该,但如果你在你的例子中使用了lambda语法,我认为它不起作用(我的意思是,处理程序不会被成功取消注册)。 / p>
如果我错了,有人会纠正我,但我相信这是真的,因为使用lambda语法有效地创建了一个新的EventHandler<CustomerChangedEventArgs>
对象,它在内存中有自己的位置。当您尝试删除此处理程序时,再次使用lambda语法,这将创建另一个新EventHandler<CustomerChangedEventArgs>
对象,该对象不等于您创建的第一个对象;所以第一个永远不会被取消注册。
可悲的是,我认为您需要实际定义这样的方法:
DoReload(object sender, CustomerChangedEventArgs e) {
DoReload(); // your original overload, which doesn't actually care
// about the sender and e parameters
}
这样你就可以:
MessageBus<CustomerChangedEventArgs>.MessageReceived += DoReload;
后来:
MessageBus<CustomerChangedEventArgs>.MessageReceived -= DoReload;
答案 1 :(得分:1)
是的,有问题。您的事件处理程序将导致表单对象保持引用,您必须显式取消注册事件处理程序。 lambdas使这变得不可能,你必须编写一个显式的处理程序。
此模式的名称为“Event Broker service”。它是由Microsoft的模式和实践团队发布的Composite UI Application Block的一部分。乞求,借用并窃取(如果不使用)你可以从中获得的东西。
答案 2 :(得分:0)
您可以使用弱引用来存储事件处理程序。这样,unhooked处理程序不会阻止对象的垃圾收集。
public static class MessageBus<T> where T : EventArgs
{
private static List<WeakReference> _handlers = new List<WeakReference>();
public static event EventHandler<T> MessageReceived
{
add
{
_handlers.Add(new WeakReference(value));
}
remove
{
// also remove "dead" (garbage collected) handlers
_handlers.RemoveAll(wh => !wh.IsAlive || wh.Target.Equals(value));
}
}
public static void SendMessage(object sender, T message)
{
foreach(var weakHandler in _handlers)
{
if (weakHandler.IsAlive)
{
var handler = weakHandler.Target as EventHandler<T>;
handler(sender, message);
}
}
}
}