承诺相当于C#

edd*_*P23 57 c# future task promise async-await

在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);
Run Code Online (Sandbox Code Playgroud)

我知道这可能不是C#的正确模式,但我无法找到一种合理的方法来实现同样的东西,即使是有些不同的模式.

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

Ste*_*ary 85

在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);
Run Code Online (Sandbox Code Playgroud)

"定时异步等待"有点尴尬,但它在现实世界的代码中也相对不常见.对于单元测试,我只是做一个常规的异步等待:

var promise = new TaskCompletionSource<MyResult>();

handlerMyEventsWithHandler(msg => promise.TrySetResult(msg));

var myResult = await promise.Task;

Assert.Equals("my header", myResult.Header);
Run Code Online (Sandbox Code Playgroud)

  • @StevenLiekens:我同意超时通常更好地表示为取消令牌; 但是,这对于使用超时取消操作的情况最佳.在这种情况下,我们讨论的是取消*wait*,而不是*operation*,并且取消令牌在这种情况下更加尴尬. (4认同)

Dar*_*con 11

没有第三方库的粗略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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,通常最好使用await/ asyncto尽可能高的级别.在某些情况下,访问Resulta Task或使用Waitcan会引入死锁.

  • @SahibKhan,1. 我在他之前发帖,2. 这也是纯 C#,尽管可能不再是最佳实践。 (2认同)

Mat*_*hin 5

您可以使用C#Promises库

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

可在NuGet上获取:https://www.nuget.org/packages/RSG.Promise/


Flo*_*ida 5

这是执行 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);
Run Code Online (Sandbox Code Playgroud)

只是为了完整性 - 太大的评论。
我同意斯蒂芬·克利里的回答

但是,如果您正在围绕一些遗留代码构建外观,则可以使用它来将旧 API 包装在任务中,例如:

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);
Run Code Online (Sandbox Code Playgroud)