您能想到.NET中具有同步上下文的事件模式吗?

tha*_*alm 2 .net c# events multithreading

主要问题是,从一个线程引发事件可以调用仅在某个线程上下文中调用的委托.在对这个问题进行一些研究后,我想,也许它可以传递某种同步上下文以及每个订阅事件:

SomeClass.SmartSyncEvent += (myDelegate, someReferenceToAThread);
Run Code Online (Sandbox Code Playgroud)

然后提出事件,它以某种方式:

foreach(subscriber)
{
    someReferenceToAThread.Invoke(myDelegate);
}
Run Code Online (Sandbox Code Playgroud)

这是超伪代码,但也许有人已经做过这样的事情,或者知道任何可以设置这种模式的.NET类.谢谢!

Bri*_*eon 5

执行此操作的最佳方法是通过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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这种模式类似于实现的方式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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样做要好得多,因为每个用户可以独立于其他用户进行编组.它的问题是处理程序必须是驻留在ISynchronizeInvoke类中的实例方法.此外,Delegate.Target静态方法为null.这就是我使用自定义add访问器强制执行该约束的原因.


如果Delegate.Target为null,则可以使其同步执行处理程序,否则无法将其转换为有用的同步对象.这个主题有很多变化.

在WPF中,您可以代码DispatcherObject而不是代码ISynchronizeInvoke.