最好的方法是SomeClass
通过ISynchronizeInvoke
.
public class SomeClass
{
public event EventHandler SmartSyncEvent;
public ISynchronizeInvoke SynchronizingObject { get; set; }
public void RaiseSmartSyncEvent()
{
if (SynchronizingObject != null)
{
SynchronizingObject.Invoke(
(Action)(()=>
{
SmartSyncEvent();
}), null);
}
else
{
SmartSyncEvent();
}
}
}
这种模式的实现方式类似System.Timers.Timer
。它的问题是每个订阅者都将被编组到同一个同步对象上。不过,这似乎不是您想要的。
幸运的是,委托存储了应该通过Target
属性调用方法的类实例。我们可以通过在调用委托之前提取它并将其用作同步对象来利用它,当然假设它是一个ISynchronizeInvoke
自身。我们实际上可以通过使用自定义添加和删除事件访问器来强制执行此操作。
public class SomeClass
{
private EventHandler _SmartSyncEvent;
public event EventHandler SmartSyncEvent
{
add
{
if (!(value.Target is ISynchronizeInvoke))
{
throw new ArgumentException();
}
_SmartSyncEvent = (EventHandler)Delegate.Combine(_SmartSyncEvent, value);
}
remove
{
_SmartSyncEvent = (EventHandler)Delegate.Remove(_SmartSyncEvent, value);
}
}
public void RaiseMyEvent()
{
foreach (EventHandler handler in _SmartSyncEvent.GetInvocationList())
{
var capture = handler;
var synchronizingObject = (ISynchronizeInvoke)handler.Target;
synchronizingObject.Invoke(
(Action)(() =>
{
capture(this, new EventArgs());
}), null);
}
}
}
这要好得多,因为每个订户都可以独立于其他订户进行编组。它的问题是处理程序必须是驻留在ISynchronizeInvoke
类中的实例方法。此外,Delegate.Target
对于静态方法为 null。这就是我使用自定义add
访问器强制执行该约束的原因。
Delegate.Target
如果为 null 或无法转换为有用的同步对象,您可以使其同步执行处理程序。这个主题有很多变化。
在 WPF 中,您可以编写代码DispatcherObject
而不是ISynchronizeInvoke
.