问题
In addressing a question about how much to use async/await, i.e. "should all methods return Task
?", the author of this answer, Matías Fidemraizer, claims that, even if your method currently only does synchronous stuff, it should still return a task so if you make it do async stuff later, "you can turn it into actual async operations without affecting the entire code base". That makes sense, but if I'm actually awaiting something, I have to add async
to the method signature. So we're talking about going from:
public Task WhateverAsync()
{
return Task.FromResult(true);
}
to
public async Task WhateverAsync()
{
return await AwaitableSomething();
}
Is adding async
to a method signature a breaking change?
回答1:
even if your method currently only does synchronous stuff, it should still return a task
I disagree. If your method is synchronous, then it should have a synchronous API. If your method is asynchronous, then it should have an asynchronous API.
However, I would agree that synchronous methods should have a Task
-returning signature if they are defined in an interface / base class and there is a decent possibility that future implementations / overrides may want to use await
.
Is adding async to a method signature a breaking change?
Just adding async
? No, it is not. Consider the case of a Task
-returning method defined in an interface: it may be implemented either with or without async
.
However, there are some possible differences in semantics, as I describe on my blog. The most notable is that the exception handling is different. If you're not careful, a naive synchronous implementation could throw an exception directly, rather than returning a faulted task. As soon as you make that method async
, the exception would be faulting a task, and no longer thrown directly.
So, it's really a question about possible changes in semantics. I would argue that the naive synchronous semantics were wrong, since the method had an asynchronous signature. E.g., the synchronous method has an asynchronous signature, so it is reasonable for callers to assume that it will catch exceptions and return a faulted task. So, if the synchronous implementations have these (easy-to-cause) bugs, then adding async
would technically be a breaking change.
回答2:
No, this is not (really) a breaking change. Adding an async
keyword to a method is only a hint to the compiler that it should turn it into an asychronous state machine.
I'm using the following code to check the public signature of a method in LINQPad.
var method = typeof(ContainingClass).GetMethod("WhateverAsync");
method.ReturnType.Dump();
method.GetParameters().Length.Dump();
method.GetCustomAttributes().Dump();
The first two dumps return the following for both of your methods.
System.Threading.Tasks.Task
0
Meaning they return the same type of value and take the same amount of parameters. They do have different attributes though, which is technically a breaking change (but if code does depend on it, it's garbage code).
The first method has no custom attributes, while the 2nd method has the following 2 attributes: AsyncStateMachineAttribute
and DebuggerStepThroughAttribute
.
Something else you want to be aware of when working with reflection is that adding the async
keyword to a method, adds a nested private (generated) class to its containing type usually named something along the lines of <WhateverAsync>d__0
.
来源:https://stackoverflow.com/questions/44395899/is-adding-async-to-a-method-signature-a-breaking-change