所有的扩展方法都被转
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();
}
}
}
“内部初始化”是什么意思?方法不是“初始化”的东西。 –