-1

Let's say for example I have this code:

public static class MyClass
{
    private static async Task<int> GetZeroAsync()
    {
        return await Task.FromResult(0);
    }
    public static int GetZero()
    {
        return GetZeroAsync().Result;
    }
}

In GetZero(), I am directly reading from the .Result property of the Task that's returned from GetZeroAsync(). Is it safe to read directly from the .Result property, since the returned Task is already completed (i.e. will it incur any deadlocks, thread duplication, or context synchronization issues)?

The reason I'm asking is because after reading all of the answers at How to call asynchronous method from synchronous method in C#? as well as Stephen Cleary's article here https://msdn.microsoft.com/en-us/magazine/mt238404.aspx, it makes me anxious to use .Result.

user3163495
  • 2,425
  • 2
  • 26
  • 43
  • No, it is not safe in most cases, as mentioned in the linked question and article. In some rare cases, it "can" be safe, but that entirely depends on your use case and environment. The more important question is, do you need both the sync and async methods? – David L May 20 '22 at 18:43
  • await Task.FromResult? Is there anything reasonable behind that? – Wiktor Zychla May 20 '22 at 18:46
  • 2
    If you always know that a method is returning `Task.FromResult`, then why is that method returning a task in the first place? – Kirk Woll May 20 '22 at 18:46
  • 1
    `Task.FromResult(0).Result` is safe, what you have is not equivalent. – ScottyD0nt May 20 '22 at 18:49

1 Answers1

1

Yes, it is safe to get the Result of a completed task. But if the correctness of your program relies on the task being completed, then you have a fragile code-base. At least you should verify this assertion during debugging:

public static int GetZero()
{
    var task = GetZeroAsync();
    Debug.Assert(task.IsCompleted);
    return task.Result;
}

You might consider adding instead a run-time check. A program that crashes is arguably better than a program that deadlocks.

public static int GetZero()
{
    var task = GetZeroAsync();
    if (!task.IsCompleted)
        throw new InvalidOperationException("The task is not completed.");
    return task.Result;
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104