【问题标题】:Use actions inside AsyncCallback在 AsyncCallback 中使用操作
【发布时间】:2015-11-17 18:24:34
【问题描述】:

我的班级执行以下操作(简化):

public void Startup(Action myAction)
{
    _myAction = myAction;
}

private void EstablishApplicationEndpoint()
{
    ...
    ApplicationEndpoint.BeginEstablish(OnApplicationEndpointEstablishCompleted, null);
}

private void OnApplicationEndpointEstablishCompleted(IAsyncResult result)
{
    try
    {
        ...
        _myAction();
    }
    catch (Exception exception)
    {
        Console.WriteLine(exception);
    }
}

BeginEstablish 方法将AsyncCallback 作为第一个参数。

但是 myAction 从未执行(我使用控制台应用程序中的类)。该操作应该向控制台输出一些内容并读取一行,但控制台会立即关闭。

我的控制台应用程序:

static void Main(string[] args)
{
    StartPlatform();
}

private static void StartPlatform()
{
    ...
    _platformController.Startup(SendContext);
}

private static void SendContext()
{
    Console.WriteLine("Press ENTER to send context");
    Console.ReadLine();
    ...
}

由于控制台不知道ReadLine- 调用会在某个时间自动关闭。我该如何防止这样做?

【问题讨论】:

  • 为什么你认为它从未被执行?这个动作有什么作用?你看到了什么行为?
  • 该动作应该向控制台输出一些内容并读取一行,但控制台立即关闭。
  • 你如何调用你的代码?向我们展示Main 方法。一般来说,建议您为您的问题创建一个minimal reproducible example
  • 您是否在某个时候调用了相应的EndEstablish 方法?如果不是,那么您的控制台应用程序将在不等待回调的情况下退出,因为BeginEstablish 方法会立即将控制权返回到下一条语句。
  • 我想我知道为什么。控制台无法“预测”ReadLine 调用即将到来(它是异步的),因此它会立即关闭。

标签: c# asynchronous delegates asynccallback


【解决方案1】:

您正在使用“异步编程模型 (APM)”模式: https://msdn.microsoft.com/en-us/library/ms228963(v=vs.110).aspx

此模型的典型代表是使用BeginEnd 方法。

请注意,当调用Begin 方法(例如您的BeginEstablish)时,回调方法表示的工作被安排在单独的(后台)线程上发生,程序控制立即返回 在主线程中。

假设其他计算可能发生在主线程上,在某个时候回调将在后台线程上完成,然后后台线程的结果将重新加入主线程。

重新加入的机制是调用相应的End 方法(因此在您的情况下,调用EndEstablish)。因此,为了防止控制台应用程序由于对BeginEstablish 的调用立即返回控制而退出,您需要执行以下操作:

  • 维护对从Begin 调用返回的IAsyncResult 对象的引用
  • 在调用Begin之后的代码路径中的某个点,调用对应的End,传入从调用Begin获得的IAsyncResult对象
  • 可以选择使用Begin 调用的第二个参数来管理状态

这可能是这样的:

private IAsyncResult EstablishApplicationEndpoint()
{
    ...
    return ApplicationEndpoint.BeginEstablish(OnApplicationEndpointEstablishCompleted, null);
}

...

private static void StartPlatform()
{
    ...
    _platformController.Startup(SendContext);
    var asyncResult = _platformController.EstablishApplicationEndpoint();

    // Do other things

    // Re-join the callback
    ApplicationEndpoint.EndEstablish(asyncResult);
}

请记住,如果在调用 End 时回调尚未完成,End 将在此时阻塞并等待回调完成。

由于您的回调正在与控制台交互,我怀疑这意味着对您的情况的调用 End 将被阻止。

【讨论】:

    猜你喜欢
    • 2013-04-23
    • 2018-02-05
    • 1970-01-01
    • 2017-04-20
    • 2014-03-21
    • 2013-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多