0

所以我在库中编写了一堆或多线程的代码,这些代码将在后台运行。所以我让 UI 传入 SynchronizationContext 对象,这样我就可以将事件发布回主 UI 线程。

许多不同的对象都有 UI 可以订阅的公共事件。我最初只是将 SyncContext 对象作为参数添加到初始化我的库的创建调用中。一旦传入,我将它存储在静态类的静态变量中,从而使其全局可访问(尽管它是内部的)。

我喜欢这样,因为每当我需要在 UI 线程上运行一些代码时,我都可以轻松地做到这一点,而无需修改太多代码。但这意味着我的很多代码都依赖于不明确的静态类。使依赖项显式需要大量代码更改以将其添加到使用该变量的任何类的构造函数中,并将对它的引用存储在任何类中,甚至创建需要它的对象。

所以我有选择

A) 为我的 SynchronizationContext 隐藏依赖项的静态变量

B) 几乎每个班级都知道并绕过我的 SynchronizationContext。

对于这种情况,还有另一种更好的模式吗?

.net 框架 3.5。主 UI 将是 WPF,但我们希望它也可以与 winforms 一起使用。

4

1 回答 1

1

如果您知道您的库只会在单个同步上下文中使用,那么我认为没有理由不能使用静态成员(您的选项 A)捕获同步上下文。

为什么您认为需要使这种依赖关系“显式”?

选项 A 可能存在问题的地方是,您的库是否可以同时从多个同步上下文中使用。(例如在它们自己的线程和消息泵上运行的多个 UI 窗口)。不过这很不寻常——大多数情况下,您只有一个 UI 线程和一个同步上下文。

此外,如果应用程序希望在不强制序列化到 UI 线程(通过同步上下文)的情况下处理某些事件,则它不能这样做。

如果这些问题对您的图书馆来说不是问题,那么选项 A 应该是可行的。

编辑 - 回应评论:

Joel,我不确定这是否对您所描述的内容有所帮助,但是如果您有时想要使用显式同步上下文,您可能需要考虑的一件事是使用线程本地存储来存储参数而无需创建重写方法以获取参数。

例如,过去我自己需要允许我的 API 的调用者既使用当前调用线程的默认同步上下文,又显式设置不同的同步上下文。我可以采取的一种方法是提供允许传递同步上下文参数的 API 方法的重载。在我的情况下,这将非常难看,因为这意味着为相当少见的用例创建大量方法重载。

所以,我所做的是创建一个类来处理创建一个“范围”,在此期间当前同步上下文被覆盖(从而有效地将其传递给被调用的方法)。该类负责(按顺序)1)缓存当前同步上下文,2)将当前上下文设置为调用者指定的同步上下文,以及 3)在“范围”末尾重置同步上下文。

这是它的样子:

public class SyncContextScope : IDisposable
{
    SynchronizationContext m_contextOnEntry;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="useContext"></param>
    public SyncContextScope(SynchronizationContext useContext)
    {
        m_contextOnEntry = SynchronizationContext.Current;
        SynchronizationContext.SetSynchronizationContext(useContext);
    }

    #region IDisposable Members

    void IDisposable.Dispose()
    {
        SynchronizationContext.SetSynchronizationContext(m_contextOnEntry);
    }

    #endregion
}

你像这样使用它:

using(new SyncContextScope(yourSyncContext))
{
   yourApi.CallSomeMethod();
}

您的 API 方法(在上面的示例 CallSomeMethod 中)现在可以使用 SynchronizationContext.Current(它使用 TLS 来存储同步上下文)。所有这些都无需求助于提供 sychronizationcontext 参数。

于 2009-12-28T17:12:30.107 回答