【问题标题】:Promisify / async-await callback in c#C# 中的 Promisify / async-await 回调
【发布时间】:2018-10-16 15:14:32
【问题描述】:

我有一个带有如下签名的 c# 函数: Foo(List<int> data, Action<string> endAction)

我无法更改 Foo(它是一个外部库)。

我是c#的新手,这几年主要是在做JS开发,不知道有没有类似JS-land中所谓的“promisify”的东西。也就是说,使调用'Foo'的函数异步并等待Foo调用endAction回调。

【问题讨论】:

  • 无论你做什么Foo都会同步运行。如果您不想阻止 UI,则可以使用 Task.Run 卸载工作。但这不会将方法更改为异步,它将保持同步。
  • @JSteward,这就是答案。我建议扩展一点并写一个实际的答案。
  • 您应该在 C#、JS 或伪代码中提供您希望如何调用该方法的示例。
  • 下面 Tom Deseyn 的答案是我最想要的。基本上 Foo 正在另一个线程中做一些工作,并在完成时调用“endAction”。我只想await Foo() 在调用 endAction 时返回。

标签: c# .net .net-core async-await


【解决方案1】:

您可以按如下方式制作 'promisify' Foo:

static Task<string> FooAsync(List<int> data)
{
    var tcs = new TaskCompletionSource<string>();
    Action action = () => Foo(data, result => tcs.SetResult(result));
    // If Foo isn't blocking, we can execute it in the ThreadPool:
    Task.Run(action);
    // If it is blocking for some time, it is better to create a dedicated thread
    // and avoid starving the ThreadPool. Instead of 'Task.Run' use:
    // Task.Factory.StartNew(action, TaskCreationOptions.LongRunning);
    return tcs.Task;
}

现在你可以调用它了:

string result = await FooAsync(myList);

【讨论】:

    【解决方案2】:

    在 C#/.NET 中没有类似 promisify 的内置方法,但您可以使用 TaskCompletionSource 的实例来创建可以在调用回调时完成的 Task

    TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
    Foo(list, (string callbackData) => { tcs.SetResult(callbackData); });
    string result = await tcs.Task;
    

    【讨论】:

    • 第一行和第三行完全是多余的。 Foo() 仍然阻塞。
    猜你喜欢
    • 2018-03-24
    • 1970-01-01
    • 2019-05-30
    • 2019-12-29
    • 2016-12-12
    • 1970-01-01
    • 1970-01-01
    • 2022-08-22
    • 1970-01-01
    相关资源
    最近更新 更多