现在我做:
Util.AssertBackgroundThread();
或
Util.AssertUIThread();
在方法的开头。这不是太糟糕,但它是运行时错误检查。我们使用像C#这样的静态语言的原因是为了将更多的错误检查移到编译器的肩膀上。
现在我认为这通常不容易,但是如果我将自己限制为仅从我自己的实用程序方法启动线程(或使用ThreadPool.QueueUserWorkItem),那么在我看来,如果我标记这些方法,它应该是否可以进行静态分析以验证仅在UI线程上运行的方法确实只在UI线程上运行?
这里有两个问题。
答案 0 :(得分:5)
我一直很喜欢这种模式:
public void GuiMethod(object param)
{
if(this.InvokeRequired)
{
this.Invoke(delgateToGuiMethod, params,...)
}
else
{
//perform gui thread method
}
}
您要受到惩罚以进行调用和检查,但您可以保证该方法在gui线程上运行,或者将使用此模式调用gui线程。
答案 1 :(得分:2)
我能想到的唯一帮助你的是让你的断言在他们的身体中使用#if DEBUG
,以便释放时方法是空的。
e.g。
public static void AssertUIThread()
{
#if DEBUG
//the code goes here
#endif
}
这样,您可以在开发期间检查是否正确调用方法,JIT将完全在生产代码中删除调用。
我目前还没有在编译时看到这样做的方法,但是我希望能够回答这个问题。
修改强>
我越是想到它,我认为你可以使用自定义FxCop规则后编译来做你想做的事情。问题是......我不知道FxCop提供的Introspection API,并且没有很好的文档记录。或者更确切地说,它根本没有记录。我能为您做的最好的事情是提供a tutorial或two可能会或可能不会帮助您。我现在正在阅读它们;如果我发现有趣的东西,我会发布它。
编辑2:
AHAH!您可以分析the caller and the callees of a method。使用那里指定的教程,专门为应始终从UI线程调用的方法创建一个属性,为另一个应该从单独的线程调用的方法创建另一个属性。您的自定义规则会检查其中一个属性,并仅在方法具有该属性时运行。然后它分析该方法的调用者(及其调用者,等等,递归),直到它可以确定调用者是在UI线程上还是从新线程。
现在我们来到了棘手的部分。我还没有把这个部分搞清楚,我留给你看看你能想出什么,因为它已经很晚了,我不能花很多时间来解决这个问题,但我对它非常感兴趣解决方案。我一直遇到的问题是线程都是使用委托开始的,我觉得这些委托的调用者链会有进一步的麻烦。我不知道是否有可能 代表;如果可能,可以将委托类型与已知的线程委托进行比较,以确定是否在新线程上进行了调用。
即使这是可能的,也会出现通过委托的问题。如果你不能,你只能确定第一个代表是否有新东西。
所以,要解决的问题。但是,希望是你迈出的第一步。