想知道,使用Task<T>
的扩展方法会不会有任何问题:
public static T Await<T>(this Task<T> task)
{
var result = default(T);
Task.Run(async () => result = await task).Wait();
return result;
}
对于那些您希望从Task
获得结果的情况,这似乎是一个不错的节省时间,但您在未使用async
标记的方法中。
答案 0 :(得分:5)
你的代码将不会像你想要的那样工作,因为你正在传递一个&#34; Hot Task&#34;到功能。
我认为你这样做的原因是为了防止只是调用task.Result
的死锁。发生死锁的原因是您阻止了UI线程,并且任务的捕获同步上下文使用UI线程进行回发。问题是当任务开始时没有等待它时捕获上下文。
所以,如果你在你的UI线程上做了
Task<Foo> task = SomeMethodAsync();
Foo result = task.Await();
您仍然会陷入僵局,因为SynchronizationContext
捕获的SomeMethodAsync()
是UI上下文,await
内部SomeMethodAsync()
内部.ConfiguerAwait(false)
不使用.Wait()
}将尝试使用将在Await()
中Func<Task<T>>
调用阻止的UI线程。
可靠地使其工作的唯一方法是,如果方法采用Task<T>
而不是public static T BlockWithoutLockup<T>(Func<Task<T>> task)
{
T result;
if(SynchronizationContext.Current != null)
{
//We use ".GetAwaiter().GetResult()" instead of .Result to get the exception handling
// like we would if we had called `await` or the function directly.
result = Task.Run(task).GetAwaiter().GetResult();
}
else
{
//If we are on the default sync context already just run the code, no need to
// spin up another thread.
result = task().GetAwaiter().GetResult();
}
return result;
}
,则可以在后台线程中启动任务以确保同步上下文不是集。
J
o
h
n
S
m
i
t
h