所有的擴展方法都被轉
var result = myTask.TimeoutAfter(TimeSpan.FromSecconds(5));
中
var result = ExtensionMethodClass.TimeoutAfter(myTask, TimeSpan.FromSecconds(5));
,別無其他。因此,函數是否是擴展方法根本不會影響它的行爲,這只是讓程序員不必從上面的例子中輸入長版本的說服。
至於如果您的代碼是線程安全的,首先您需要了解「線程安全」的含義。我強烈建議您閱讀Eric Lippert撰寫的文章「What is this thing you call "thread safe"?」,它將極大地幫助您瞭解線程安全的含義。
您的代碼不訪問或改變其範圍內的任何外部變量,因此該函數本身是線程安全的,但這並不意味着它不能用於「線程不安全」的方式。幸運的是,您很幸運,Task
和TimeSpan
都確保您的所有方法和屬性都具有安全性,因此您不太可能遇到任何線程安全問題。
然而所有這一切,你有一個錯誤的競爭條件。如果task.IsCompleted
返回true並且task
引發異常,您將永遠不會收到該異常的通知。同樣,如果timeSpan == Timeout.InfiniteTimeSpan
即使傳入的任務仍在運行,你的函數也會立即返回一個已完成的任務。即使您不打算超時,您也需要await
任務。此外,你的try /終於可以simplifed到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();
}
}
}
「內部初始化」是什麼意思?方法不是「初始化」的東西。 –