获取 EventHandler 以在原始线程上调用 Invoke()

Get EventHandler to call Invoke() on original thread

我正在使用 System.Threading.Timer 异步重复某个任务。当任务准备就绪时,应执行原始线程(调用 Start() 的地方)上的方法。

public event EventHandler StatusChanged;

public void Start()
{
    StatusChanged += new EventHandler(SomethingChangedMethod);
    new Timer(Pending, null, 0, 1000);
}

private void Pending(object state)
{
    //Do Something
    StatusChanged?.Invoke(this, EventArgs.Empty);
}

因为我不在控件上什么的,所以我不能调用Invoke()BeginInvoke()

首先,您可能无法 post 向调用 Start 的线程发送消息:您只能在线程具有消息队列的情况下执行此操作与之关联,并正在检查该队列。 UI 个线程执行此操作,但是例如线程池线程或您使用 new Thread() 创建的线程不会。

如果线程有与之关联的消息队列,通常的做法是在该线程上安装 SynchronizationContext。您可以使用 SynchronizationContext.Current 获取线程的 SynchronizationContext,将其存储起来,然后使用 SynchronizationContext 将 post 消息发送到该线程的消息队列。如果线程没有安装 SynchronizationContextSynchronizationContext.Current returns null.

public event EventHandler StatusChanged;
private Timer timer;
private SynchronizationContext synchronizationContext;

public void Start()
{
    synchronizationContext = SynchronizationContext.Current;
    StatusChanged += new EventHandler(SomethingChangedMethod);
    timer = new Timer(Pending, null, 0, 1000);
}

private void Pending(object state)
{
    // Do Something
    if (synchronizationContext != null)
    {
        synchronizationContext.Post(_ => StatusChanged?.Invoke(this, EventArgs.Empty), null);
    } 
    else
    {
        StatusChanged?.Invoke(this, EventArgs.Empty);
    }
}

Since Start() can be called from outside the library I have no real control about that.

作为图书馆作者,您不知道什么是正确的做法。众所周知,原来的线程刚刚开始调用 Start 并在很久以前就退出了。你不知道回到“同一个”“线程”是正确的行为,所以当然,是的,你把它留给你的消费者。

以同样的方式,作为一个库作者,你不应该固定选择使用什么日志框架,是否以及如何向用户显示错误消息(如果有用户的话)等。

做简单的事情,发起你的活动,让为应用程序挑选框架的人做出正确的选择。因为你不应该(不一定会损害图书馆的潜在消费者)