查了TaskOfResult.cs的源码(Source code of TaskOfResult.cs):
如果Task没有完成,Task.Result会调用getter中的Task.Wait()方法。
public TResult Result
{
get
{
// If the result has not been calculated yet, wait for it.
if (!IsCompleted)
{
// We call NOCTD for two reasons:
// 1. If the task runs on another thread, then we definitely need to notify that thread-slipping is required.
// 2. If the task runs inline but takes some time to complete, it will suffer ThreadAbort with possible state corruption.
// - it is best to prevent this unless the user explicitly asks to view the value with thread-slipping enabled.
//#if !PFX_LEGACY_3_5
// Debugger.NotifyOfCrossThreadDependency();
//#endif
Wait();
}
// Throw an exception if appropriate.
ThrowIfExceptional(!m_resultWasSet);
// We shouldn't be here if the result has not been set.
Contract.Assert(m_resultWasSet, "Task<T>.Result getter: Expected result to have been set.");
return m_result;
}
internal set
{
Contract.Assert(m_valueSelector == null, "Task<T>.Result_set: m_valueSelector != null");
if (!TrySetResult(value))
{
throw new InvalidOperationException(Strings.TaskT_TransitionToFinal_AlreadyCompleted);
}
}
}
如果我们调用Task的GetAwaiter方法,Task将包裹TaskAwaiter<TResult>(Source code of GetAwaiter()),(Source code of TaskAwaiter):
public TaskAwaiter GetAwaiter()
{
return new TaskAwaiter(this);
}
如果我们调用TaskAwaiter<TResult>的GetResult()方法,它将调用Task.Result属性,即Task.Result将调用Task的Wait()方法(Source code of GetResult()):
public TResult GetResult()
{
TaskAwaiter.ValidateEnd(m_task);
return m_task.Result;
}
是ValidateEnd(Task task)(Source code of ValidateEnd(Task task))的源码:
internal static void ValidateEnd(Task task)
{
if (task.Status != TaskStatus.RanToCompletion)
HandleNonSuccess(task);
}
private static void HandleNonSuccess(Task task)
{
if (!task.IsCompleted)
{
try { task.Wait(); }
catch { }
}
if (task.Status != TaskStatus.RanToCompletion)
{
ThrowForNonSuccess(task);
}
}
这是我的结论:
可以看出GetResult() 正在调用TaskAwaiter.ValidateEnd(...),因此Task.Result 与GetAwaiter.GetResult() 不同。
我认为GetAwaiter().GetResult() 是比.Result 更好的选择,因为它不包含异常。
我在 C# 7 in a Nutshell(Joseph Albahari 和 Ben Albahari)一书的第 582 页读到此内容
如果前面的任务出错,则在执行任务时重新抛出异常
继续代码调用 awaiter.GetResult() 。而不是打电话
GetResult ,我们可以简单地访问 Result 的属性
前因。调用GetResult 的好处是,如果
先行错误,直接抛出异常而不被
包裹在 AggregateException 中,允许更简单和更清洁
抓块。
来源:C# 7 in a Nutshell's page 582