C# 为什么在发布到WindowsFormsSynchronizationContext时会动态调用SendOrPostCallback委托?

C# 为什么在发布到WindowsFormsSynchronizationContext时会动态调用SendOrPostCallback委托?,c#,.net,winforms,synchronization,synchronizationcontext,C#,.net,Winforms,Synchronization,Synchronizationcontext,我正在编写一个包装器,它允许我在任意SynchronizationContext上调用方法,例如,允许我将与网络相关的回调(例如Socket.BeginReceive)排入队列,以接收某些任意调度器/处理程序,例如UI线程,或我自己设计的用于串行执行的实现。为了避免需要同步数据结构-锁等 基本上是这样的: .. 公共无效BeginInvokeMethodCall methodCall { this.synchronizationContext.Postthis.SynchronizationCo

我正在编写一个包装器,它允许我在任意SynchronizationContext上调用方法,例如,允许我将与网络相关的回调(例如Socket.BeginReceive)排入队列,以接收某些任意调度器/处理程序,例如UI线程,或我自己设计的用于串行执行的实现。为了避免需要同步数据结构-锁等

基本上是这样的:

.. 公共无效BeginInvokeMethodCall methodCall { this.synchronizationContext.Postthis.SynchronizationContextCallback,methodCall; } 私有void SynchronizationContextCallbackObject方法调用 { methodCall作为methodCall.Invoke; } .. 在aWindowsFormsSynchronizationContext中一切似乎都很好,但当抛出异常时,System.Reflection.TargetInvocationException我意识到SendOrPostCallback委托正在被动态调用?!以下是System.Windows.Forms.Control.ThreadMethodEntry类中的相关Microsoft参考代码:

私有静态void invokeMarshaledCallBackDotThreadMethodEntry tme { //为了提高速度,我们缩短了两种常见的情况。 // 如果tme.method是EventHandler { 如果tme.args==null | | tme.args.Length<1 { EventHandlertme.methodtme.caller,EventArgs.Empty; } 否则,如果tme.args.Length<2 { EventHandlertme.methodtme.args[0],EventArgs.Empty; } 其他的 { EventHandlertme.methodtme.args[0],EventArgstme.args[1]; } } 否则,如果tme.method是MethodInvoker { methodinvokerTime.method; } 否则,如果tme.method是WaitCallback { Debug.Asserttme.args.Length==1, WaitCallback的参数是错误的; WaitCallbacktme.methodtme.args[0]; } 其他的 { tme.retVal=tme.method.DynamicInvoketme.args; } }
似乎不支持SendOrPostCallback委托,但有趣的是,它的签名与WaitCallback完全相同!或者更一般地说,一种行为。这让我有个疑问,我是不是做错了什么?还是这是故意的?在语言和框架层面,我的意思是。。。明显地动态调用所有已调度的方法调用将大大降低调试速度和难度?我甚至觉得这不是一个可用的解决方案?。我缺少什么?

这是不可避免的,它可以封送任何委托类型。唯一的方法就是使用DynamicVoke。他们确实努力挑选了一些您在Winforms编程中使用的常见委托类型,但如果不失去这样做的好处,这永远不会是一个详尽的列表。不用担心成本,这总是涉及线程上下文切换和Winforms消息循环响应PostMessage的延迟。相比之下,DynamicVoke的成本微不足道


是的,你必须做一些事情来避免被最外层的异常所击打,TargetInvocationException对任何人都没有用处。Winforms Control.Invoke方法通过仅重新引发最内部的异常来实现这一点。这也不太理想,但比领带要好。

谢谢你的回答!虽然我仍然觉得很奇怪,SendOrPostCallback没有被认为是Winforms编程中常用的委托类型。。如果有可能的解决方案:也许我会添加对ISynchronizeInvoke的支持?旧的接口?。无论如何我将尽最大努力避免那些似乎也会减少堆栈跟踪的TargetInvocationException错误。我们必须找到TargetInvocationException调试问题的解决方案!在VS选项中:调试->常规在异常跨越AppDomain或托管/本机边界时启用中断。现在,调试器正确捕获未处理的异常!