すべての拡張メソッドはないが
var result = ExtensionMethodClass.TimeoutAfter(myTask, TimeSpan.FromSecconds(5));
何もないので
var result = myTask.TimeoutAfter(TimeSpan.FromSecconds(5));
を回しています。したがって、関数が拡張メソッドであるかどうかに関わらず、その動作にはまったく影響はありません。プログラマが上記の例から長いバージョンをタイプする必要はないというだけのことです。
コードがスレッドセーフであるかどうかについては、まず「スレッドセーフ」が何を意味するのかを理解する必要があります。 Eric Lippertの記事「What is this thing you call "thread safe"?」を読むことを強くお勧めします。これは、スレッドの安全性の意味を理解するのに大いに役立ちます。
コードは外部変数をスコープからアクセスまたは変更しないため、関数自体はスレッドセーフですが、スレッドセーフではありません。幸いなことに、Task
とTimeSpan
は、すべてのメソッドとプロパティで安全性が保証されているため、スレッドセーフの問題が発生する可能性は低いです。
しかし、言われていることはすべて競合状態のバグです。 task.IsCompleted
がtrueを返し、task
が例外をスローすると、その例外は通知されません。 timeSpan == Timeout.InfiniteTimeSpan
あなたの関数は、渡されたタスクがまだ実行中であっても、immedatly完了したタスクを返します。タイムアウトを計画していなくても、await
タスクが必要です。あなたはまだそれを行っていない場合にも、あなたの試みは/最後に、using
声明
public static async Task TimeoutAfter(this Task task, TimeSpan timeSpan)
{
using(var cts = new CancellationTokenSource())
{
if (task.IsCompleted || timeSpan == Timeout.InfiniteTimeSpan)
{
await task;
return;
}
if (timeSpan == TimeSpan.Zero)
throw new TimeoutException();
if (task == await Task.WhenAny(task, Task.Delay(timeSpan, cts.Token)))
{
cts.Cancel();
await task;
}
else
{
throw new TimeoutException();
}
}
}
最後に簡体することができますが、そのタスクをタイムアウトしたい場合には、あなたもTask<T>
にかかるバージョンを作成したいと思うでしょう結果を返します。
public static async Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeSpan)
{
using(var cts = new CancellationTokenSource())
{
if (task.IsCompleted || timeSpan == Timeout.InfiniteTimeSpan)
{
return await task
}
if (timeSpan == TimeSpan.Zero)
throw new TimeoutException();
if (task == await Task.WhenAny(task, Task.Delay(timeSpan, cts.Token)))
{
cts.Cancel();
return await task;
}
else
{
throw new TimeoutException();
}
}
}
「内部で初期化された」とはどういう意味ですか?メソッドは「初期化された」ものではありません。 –