Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Task.Result with await Task #734

Open
AmadeusW opened this issue Mar 3, 2016 · 6 comments · May be fixed by #820
Open

Replace Task.Result with await Task #734

AmadeusW opened this issue Mar 3, 2016 · 6 comments · May be fixed by #820

Comments

@AmadeusW
Copy link

AmadeusW commented Mar 3, 2016

New analyzer: Replace Task.Result with await and make method async Task

Recently we've found some deadlocks in our code. They were caused by a stray .Result in situations when there was an async method earlier in the call stack. Using .Result is considered a bad practice.
I propose an analyzer that removes .Result and replaces it with an await call

Before:

private async Task<bool> DoSomethingAsync()
{
    return AsyncMethod().Result;
}

After:

private async Task<bool> DoSomethingAsync()
{
    return await AsyncMethod();
}

Category: Design
Severity: Warning
Diagnostic id: CC0122

I'm curious what's your opinion on

  1. This refactoring will cause a build error, because method's signature changes
  2. Are there any use cases where using .Result is OK?
@giggio
Copy link
Member

giggio commented Mar 14, 2016

If we do this, we would need to change all the callers to also be async. We can't cause a build problem after. This means cascade into several parts of the program. This is a huge task.
I actually like it.
Using .Result is ok in several situations, when you can control the program flow. A console app that is calling into an async only API will have to .Result, for example.
Also, it would be a good idea to rename the function to end with Async.

Because of the cascading problem, I think we need to discuss it.

@AmadeusW
Copy link
Author

Yes, this can introduce a huge change to the solution. Some functions can not be made async - for example, Main in console applications. Also, async event handlers that return void could crash the process with unhandled exceptions.

The more I think about this concept, the more I like it, too. After all, turning a program async is a pragmatic and menial task.

@SriramSakthivel
Copy link

If the method is already async and still uses task.Result, we could add a warning and provide code fix which converts the task.Result to await task

@AmadeusW
Copy link
Author

I think this would be fair. This way, we won't cascade the conversion to async and introduce massive build errors.
It won't catch deadlocks caused by async method calling non-async method with .Result, but I think it would be a good start.
I can take a shot at implementing it if everyone is ok with this.

@giggio
Copy link
Member

giggio commented Apr 17, 2016

@AmadeusW I am ok with it, as long as the method already has the modifier async. So we can't change an async method that returns a Task directly, ok?
Later we can evolve this to be more ambitious and solve the original problem.
Go for the implementation, then, @AmadeusW.

@AmadeusW
Copy link
Author

AmadeusW commented Jul 4, 2016

@giggio @ElemarJR @carloscds pinging you because the guidelines say that I should notify you before creating a PR.
I think I've got it working. Check it out at master...AmadeusW:0122
Screenshot of a non trivial case:
cc0122

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

3 participants