C# 在C中处理跨线程事件的最佳方法是什么#

C# 在C中处理跨线程事件的最佳方法是什么#,c#,.net,multithreading,events,invoke,C#,.net,Multithreading,Events,Invoke,我正在尝试开发一种从线程触发事件并在主UI线程上处理事件的方法。在事件处理程序中,我将更新UI,而不必到处检查InvokeRequired 我从搜索中看到了很多关于这方面的内容,但是我还没有看到任何地方的例子能够100%地解决可能出现的问题。我想出了一个似乎可行的解决方案,就我所知,它解决了我所读到的各种问题。我很想听听人们对这方面的看法: public static void SafeInvoke<T>(this EventHandler<T> source, obje

我正在尝试开发一种从线程触发事件并在主UI线程上处理事件的方法。在事件处理程序中,我将更新UI,而不必到处检查InvokeRequired

我从搜索中看到了很多关于这方面的内容,但是我还没有看到任何地方的例子能够100%地解决可能出现的问题。我想出了一个似乎可行的解决方案,就我所知,它解决了我所读到的各种问题。我很想听听人们对这方面的看法:

public static void SafeInvoke<T>(this EventHandler<T> source, object sender, T args) where T : System.EventArgs
{
    EventHandler<T> handler;

    lock (SyncRoot)
    {
        handler = Volatile.Read(ref source);
    }

    if (handler == null)
    {
        return;
    }

    foreach (Delegate d in handler.GetInvocationList())
    {
        ISynchronizeInvoke target = d.Target as ISynchronizeInvoke;

        if (target == null)
        {
            continue;
        }

        if (target.InvokeRequired)
        {
            target.BeginInvoke(d, new[] { sender, args });
        }
        else
        {
            handler(sender, args);
        }
    }
}
publicstaticvoidsafeinvoke(此EventHandler源、对象发送方、T args),其中T:System.EventArgs
{
事件处理程序;
锁定(同步根)
{
handler=Volatile.Read(参考源);
}
if(handler==null)
{
回来
}
foreach(handler.GetInvocationList()中的委托d)
{
ISynchronizeInvoke目标=d。目标为ISynchronizeInvoke;
if(target==null)
{
持续
}
if(target.invokererequired)
{
target.BeginInvoke(d,新[]{sender,args});
}
其他的
{
处理程序(发送方,args);
}
}
}

如果您使用的是.Net 3.5或更高版本,则可以使用被动扩展。它非常适合做这种事情


如果您使用的是.Net 3.5或更高版本,则可以使用被动扩展。它非常适合做这种事情


不需要
锁定(SyncRoot)
部分。因为
source
是作为非ref参数传递的,所以除非您显式地这样做,否则它不可能被更改。。。这似乎很明显,但我还是要提一提。invokererequired是一种方便,而不是一种要求。您永远不必检查invokererequired,因为您应该能够知道代码何时会在单独的线程中执行,何时不会。就我个人而言,我从不使用invokerrequired。我只是确保在工作线程中运行的代码段中使用Invoke,而在知道代码在GUI线程中运行时不使用Invoke。我从来没有遇到过这种方法的问题。只是想一想,你的密码坏了。当target不是
ISynchronizeInvoke
@dizzy.stackoverflow时,您忽略了函数调用。此外,
Invoke
如果从UI线程调用,效果很好,因此在(希望很少)您不知道自己是否不是UI线程的情况下,您可以调用
Invoke
,知道它会很好地工作。使线程不透明从来都不是一个错误。订阅者无法抵御事件传递不可避免的陈旧性,以及线程竞争带来的巨大开销和非零风险。至少让它成为可选的,并实现.NET framework类(如Process和FileSystemWatcher)使用的SychronizingObject模式。不需要
lock(SyncRoot)
部分。因为
source
是作为非ref参数传递的,所以除非您显式地这样做,否则它不可能被更改。。。这似乎很明显,但我还是要提一提。invokererequired是一种方便,而不是一种要求。您永远不必检查invokererequired,因为您应该能够知道代码何时会在单独的线程中执行,何时不会。就我个人而言,我从不使用invokerrequired。我只是确保在工作线程中运行的代码段中使用Invoke,而在知道代码在GUI线程中运行时不使用Invoke。我从来没有遇到过这种方法的问题。只是想一想,你的密码坏了。当target不是
ISynchronizeInvoke
@dizzy.stackoverflow时,您忽略了函数调用。此外,
Invoke
如果从UI线程调用,效果很好,因此在(希望很少)您不知道自己是否不是UI线程的情况下,您可以调用
Invoke
,知道它会很好地工作。使线程不透明从来都不是一个错误。订阅者无法抵御事件传递不可避免的陈旧性,以及线程竞争带来的巨大开销和非零风险。至少让它成为可选的,并实现SychronizingObject模式,如Process和FileSystemWatcher等.NET framework类所使用的模式。这甚至可以作为一个答案吗?它甚至一点也不接近于回答所问的问题。你说反应式扩展很好地解决了这个问题?好的,展示一些代码,或者至少是一些代码的链接,而不是什么反应式扩展的链接。这甚至可以作为一个答案吗?它甚至一点也不接近于回答所问的问题。你说反应式扩展很好地解决了这个问题?好的,展示一些代码或者至少是一些代码的链接,而不是反应式扩展的链接。