配置类型数据:静态全局变量还是传递它?

时间:2009-12-28 02:23:46

标签: design-patterns anti-patterns

所以我在库中编写了一堆或多线程代码,它们将在后台运行。所以我在SynchronizationContext对象中传递了UI,所以我可以将事件发送回主UI线程。

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

我喜欢这个,因为无论何时我需要在UI线程上运行一些代码,我都可以轻松地完成它,而无需修改很多代码。但这意味着我的很多代码都对Static类没有明确的依赖性。使依赖显式化需要很多代码更改,以将其添加到使用该变量的任何类的构造函数中,在任何甚至创建需要它的对象的类中存储对它的引用。

所以我有选择

A)隐藏我的SynchronizationContext依赖关系的静态变量

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

对于这种情况,还有其他模式会更好吗?

.net framwork 3.5。主UI将是WPF,但我们希望它也能与winforms一起使用。

1 个答案:

答案 0 :(得分: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参数。