扩展方法不等同于直接调用

时间:2016-06-07 11:42:29

标签: c# task equivalent

我想说我有以下两个代码片段是等价的,但它们不是。

以下工作正常:

var entry3 = Task.Run(async () => await entry2.GetMemberGroupsAsync(false)).WaitForResult().FirstOrDefault();

以下代码,我只是将Task.Run.WaitForResult链移动到扩展方法中,但是不起作用,但会产生死锁:

var entry3 = entry2.GetMemberGroupsAsync(false).RunSynchronouslyAndReturnResult().FirstOrDefault();

public static T RunSynchronouslyAndReturnResult<T>(this Task<T> task)
{
    return Task.Run(async () => await task).WaitForResult();
}

为什么这两个代码段不等同?

为了完整起见,GetMemberGroupsAsync方法由Microsoft Azure Graph API提供,函数WaitForResult定义如下。据我所知,根据来电者姓名或某事情,它并没有做任何不同的事情。那样:

public static TResult WaitForResult<TResult>(this Task<TResult> task,
                                             bool continueOnCapturedContext = false)
{
    if (task == null)
    {
        throw new ArgumentNullException("task");
    }

    try
    {
        return PreventForDeadLocks(task, continueOnCapturedContext).Result;
    }
    catch (AggregateException ex)
    {
        if (ex.InnerExceptions.Count == 1)
        {
            throw ex.InnerExceptions[0];
        }

        throw;
    }
}

public static async Task<TResult> PreventForDeadLocks<TResult>(this Task<TResult> task,
                                                               bool continueOnCapturedContext = false)
{
    return await task.ConfigureAwait(continueOnCapturedContext: continueOnCapturedContext);
}

2 个答案:

答案 0 :(得分:4)

这里的区别在于您的任务开始的同步上下文。这里:

var entry3 = Task.Run(async () => await entry2.GetMemberGroupsAsync(false)).WaitForResult().FirstOrDefault();

您在await entry2.GetMemberGroupsAsync(false)调用内启动异步任务(我的意思是Task.Run),因此不会捕获UI同步上下文。但是在这里:

var entry3 = entry2.GetMemberGroupsAsync(false).RunSynchronouslyAndReturnResult().FirstOrDefault();

您在UI上下文中隐式启动任务(entry2.GetMemberGroupsAsync(false)返回任务),因此捕获了UI同步上下文,并且您遇到了死锁。

答案 1 :(得分:3)

在第一种情况下,在与WaitForResult不同的线程上调用GetMemberGroupsAsync。

在第二种情况下,它在与WaitForResult相同的线程上调用。您只是在其他线程上等待