在我们的旧版VB6代码中,我们使用系统计时器来执行回调,以便可以在不阻塞事件处理程序的情况下运行状态机。一些Psuedo代码示例
Sub Unhooked(State info)
Select Case info
Case 1
NextState = somestate1
Case 2
NextState = somestate2
Case 3
NextState = somestate3
End Select
RunStateMachine
End Sub
Sub RunStateMachine()
MyObject.GoDoSomethingAndCallMeBack
End Sub
Sub MyObject_EventCallback(State info)
APITimer.SetUpCallBackTarget (Unhooked, info)
APITimer.CallMeBackInASec
End Sub
希望您了解在状态机中进行某些调用的情况,该函数将在事件处理程序被触发后生成,并设置一个计时器来执行回调,以便在我们继续之前完成事件处理程序代码到下一个州。
我在C#中继续使用类似的方法,但感觉不对,因为我确信这种语言会提供一种可行的方法。由于我的C#状态机仍在调用在UI线程上引发事件的VB6对象,是否有更好的方法来“解除”事件处理程序,以便在状态机继续运行之前释放它?
我以为我可以使用BeginInvoke向泵添加消息以运行状态机,但是在同一个线程而不是线程池线程但我的类不是表单或控件。我想我可以提出一个不使用计时器的解决方案,但是,它们很容易使用,所以任何想法都会很棒。
答案 0 :(得分:1)
要解决您的直接问题,您可以将Task
排队到UI线程上下文,例如:
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => Unhooked(info), CancellationToken.None,
TaskCreationOptions.None, ui);
即使您的对象不是表单或控件,也可以检测到UI SynchronizationContext
。有关SynchronizationContext
的详细信息,请参阅my MSDN article。
如果你的代码中有很多这个,你可能想把它包装成一个帮助方法:
public void CallbackLater(Action action)
{
Task.Factory.StartNew(action, CancellationToken.None,
TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
void MyObject_EventCallback(State info)
{
CallbackLater(() => Unhooked(info));
}
在更广泛的方案中,认真考虑Async CTP并设计Task-Based Asynchronous Pattern API而不是在UI线程上引发事件(即基于事件的异步模式)。