C# 从库中捕获主线程SynchronizationContext或Dispatcher
我有一个C#库,希望能够将工作发送/发布到“主”ui线程(如果存在)。 此库可由以下人员使用:C# 从库中捕获主线程SynchronizationContext或Dispatcher,c#,winforms,multithreading,synchronization,C#,Winforms,Multithreading,Synchronization,我有一个C#库,希望能够将工作发送/发布到“主”ui线程(如果存在)。 此库可由以下人员使用: winforms应用程序 本机应用程序(带UI) 控制台应用程序(没有UI) 在库中,我希望在初始化期间捕获一些东西(SynchronizationContext、Dispatcher、Task Scheduler或其他东西),这些东西将允许我(稍后)向主线程发送/发布工作(如果主线程具有这种能力,即它有一个消息泵)。例如,如果且仅当主应用程序能够访问主线程时,库希望在主线程上安装一些Winfor
- winforms应用程序
- 本机应用程序(带UI)
- 控制台应用程序(没有UI)
调度程序。从后台线程调用将挂起(如预期的那样)。我可以使用(如果不存在调度程序,则不会为线程创建调度程序).但是本机UI应用程序将使用此方法返回空调度程序,因此我再次无法区分UI应用程序和控制台应用程序
Initialize
方法时指定它是否是UI应用程序,但我希望尽可能避免库的用户出现这种复杂情况。我认为您应该将此作为Initialize
方法的一个选项(或者以某种方式允许您的来电者请求UI交互),对我来说,这更有意义。我不知道具体细节,但在我看来这似乎是一种“礼貌”要做的事情是,让你的调用者决定他们是想要你还是想要支持你的UI。我会更进一步,甚至作为调用者提供一个同步上下文。但这是我的观点
要回答你的问题,有几个“黑客”您可以使用来确定您是否在控制台应用程序中运行。因此,这个问题有一些相关信息:这通常是不可能的,易于在线程中使用的库无法对哪个特定线程是UI线程做出任何假设。您可以捕获同步。当前的,但这只能正常工作如果您的初始化方法是从UI线程调用的,则不会发生异常情况。这与TaskScheduler一样正常工作。FromCurrentSynchronizationContext()往往是偶然工作的,但不是保证。如果thread.CurrentThread.GetApartmentState()如果不返回STA,则您没有从UI线程被调用的可能性非常高。SynchronizationContext.Current在这种情况下也通常为null,这是另一种检查方法
(有争议的)问题更好的方法是不用担心它,让客户机代码解决它,它将不会在封送回调时遇到任何问题。或者公开SynchronizationContext类型的属性,以便客户机代码可以分配它。或者将其添加为构造函数参数。如果准备发布但发现它仍然为null,这是客户端程序员只做了一次的疏忽。更改库初始化以使用SyncronizationContext参数。如果该参数为null,则库不需要执行任何特殊操作,如果不是null,则在那里发布/发送GUI更新。我认为这正是所要做的。状态: 基于事件的异步模式提供了打包具有异步功能的类的标准化方法。如果使用帮助器类(如)实现,则您的类将在任何应用程序模型下正常工作,包括ASP.NET、控制台应用程序和Windows窗体应用程序 由调用者决定是否要在UI线程上调用您的API。如果他们这样做,这将捕获上下文,事件将按顺序通过消息泵。在控制台应用程序中,如果您安装SynchronizationContext,则可以获得相同的行为,您可以使用从
Nito.AsyncEx
nuget软件包。无需额外属性,也无需自己编写条件代码。如果没有可用的序列化同步上下文,则将使用控制台应用程序可用的假同步上下文,而控制台应用程序只是将事件排队到线程池(这意味着帖子可能不会按顺序执行)。只需记住在完成时调用AsyncOperation.OperationCompleted()
或AsyncOperation.PostOperationCompleted()
在库中,我希望在初始化期间捕获一些东西(SynchronizationContext、Dispatcher、Task Scheduler或其他东西)
这正是我们所要做的,而且是以一种环境不可知的方式