Scalaには、Futureを手動で完了するために使用できるPromiseクラスがあります。 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#の場合:
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
を可能な限り高いレベルで使用するのが最善であることに注意してください。 Result
のTask
にアクセスするか、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's answer 。
ただし、いくつかのレガシーコードの周りにファサードを構築している場合、これを使用して、次のようなタスクで古い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#で最も近いものです。