0

在我们遗留的 VB6 代码中,我们使用系统计时器来执行回调,以便状态机可以在不阻塞事件处理程序的情况下运行。一些伪代码示例

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 向泵添加一条消息以运行状态机,但在同一个线程而不是线程池线程上,但我的类不是表单或控件。我想我可以想出一个不使用计时器的解决方案,但是,它们使用起来非常简单,所以任何想法都会很棒。

4

1 回答 1

1

为了解决您的直接问题,您可以将 a 排队Task到 UI 线程上下文,例如:

var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => Unhooked(info), CancellationToken.None,
    TaskCreationOptions.None, ui);

SynchronizationContext即使您的对象不是表单或控件,也可以检测到UI 。有关详细信息SynchronizationContext,请参阅我的 MSDN 文章

如果你的代码中有很多这样的东西,你可能想把它包装成一个辅助方法:

public void CallbackLater(Action action)
{
  Task.Factory.StartNew(action, CancellationToken.None,
    TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}

void MyObject_EventCallback(State info)
{
  CallbackLater(() => Unhooked(info));
}

在更广泛的方案中,认真考虑异步 CTP并设计基于任务的异步模式 API,而不是在 UI 线程上引发事件(即基于事件的异步模式)。

于 2011-07-20T14:34:59.617 回答