c#中的Promise等价

本文关键字:等价 Promise 中的 | 更新日期: 2023-09-27 18:02:49

在Scala中有一个Promise类可以用来手动完成Future。我正在寻找c#的替代方案。

我正在写一个测试,我希望它看起来像这样:

// var MyResult has a field `Header`
var promise = new Promise<MyResult>;
handlerMyEventsWithHandler( msg =>
    promise.Complete(msg);
);
// Wait for 2 seconds
var myResult = promise.Future.Await(2000);
Assert.Equals("my header", myResult.Header);

我知道这可能不是c#的正确模式,但是我无法找到一个合理的方法来实现同样的事情,即使是用不同的模式。

编辑:请注意,async/await在这里没有帮助,因为我没有任务等待!我只是有一个访问处理程序,将运行在另一个线程。

c#中的Promise等价

在c#中:

  • Task<T>为将来值(Task为将来值)。
  • TaskCompletionSource<T>是一个承诺。

所以你的代码会翻译成这样:

// var promise = new Promise<MyResult>;
var promise = new TaskCompletionSource<MyResult>();
// handlerMyEventsWithHandler(msg => promise.Complete(msg););
handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));
// var myResult = promise.Future.Await(2000);
var completed = await Task.WhenAny(promise.Task, Task.Delay(2000));
if (completed == promise.Task)
  ; // Do something on timeout
var myResult = await completed;
Assert.Equals("my header", myResult.Header);

"定时异步等待"有点尴尬,但在实际代码中也相对不常见。对于单元测试,我将只执行常规的异步等待:

var promise = new TaskCompletionSource<MyResult>();
handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));
var myResult = await promise.Task;
Assert.Equals("my header", myResult.Header);

没有第三方库的c#等效代码是:

// var MyResult has a field `Header`
var promise = new TaskCompletionSource<MyResult>();
handlerMyEventsWithHandler(msg =>
  promise.SetResult(msg)
);
// Wait for 2 seconds
if (promise.Task.Wait(2000))
{
  var myResult = promise.Task.Result;
  Debug.Assert("my header" == myResult.Header);
}

请注意,通常最好使用await/async尽可能高的级别。访问TaskResult或使用Wait在某些情况下可能会引入死锁。

你可以使用c# Promises库

在Github上开源:https://github.com/Real-Serious-Games/C-Sharp-Promise

NuGet: https://www.nuget.org/packages/RSG.Promise/

这是做承诺的老派方式。
那时候我记得它叫同步:)

MyResult result = null;
var are = new AutoResetEvent(false);
handlerMyEventsWithHandler( 
    msg => {result = msg; are.Set();}
);
// Wait for 2 seconds
if(!are.WaitOne(2000)) {/* handle timeout... */}
Assert.Equals("my header", myResult.Header);

只是为了完整性——注释太大。
我同意Stephen Cleary的回答。

但是如果你在一些遗留代码周围构建一个facade,这可以用来在Task中包装旧的API,如:

public Task<MyResult> GetResultAsync() {
    MyResult result = null;
    var are = new AutoResetEvent(false);
    handlerMyEventsWithHandler(msg => {
        result = msg;
        are.Set();
    });
    are.WaitOne();
    return Task.FromResult(result);
}

尝试查看异步模型。任务在c#中是最接近等价的。

这里有一个链接到微软文章解释它们的使用

您可以从Nuget下载未来(https://www.nuget.org/packages/Future/)包,并可以如下使用

        Promise<int> promise = new Promise<int>();
        new Task(() =>
        {
            Thread.Sleep(100);
            promise.Set(20);
        }).Start();
        int result=promise.Get();

根据示例,您可以创建一个promise对象并执行get操作来获取结果,get将等待直到result在对象上。如上面的示例所示,从另一个线程执行set。

这个包提供了以下两个类

  1. Promise:无限等待结果

  2. timmedpromise:只等待结果到指定的时间。如果结果在时间内不可用,它抛出超时异常