When deciding whether to change an argument of a general type in any common interface, you need to consider all the uses of the argument of a general type inside the interface. Each use may result in some dispersion restrictions. It includes:
- Used as an input argument to a method - prohibits covariance
- Used as a return value from a method - prohibits contravariance
- Used as part of another generic derivation, such as
Task<T> - such use may prohibit covariance, prohibit contravariance, or both
I used negative logic to emphasize that all of these cases basically introduce restrictions. After the analysis, you will find out if any element has forbidden covariance, and then your argument cannot be declared as out . Conversely, if any element rejects contravariance, your argument may not be declared as in .
In your particular case, the first Search method returns an IEnumerable<T> , while the contravariance of the rendering is not applicable. But then SearchAsync returns Task<IEnumerable<T>> , and this use introduces restrictions that exist in the Task type - it is invariant, which means that this time out also impossible.
As a result, your common interface must be invariant in its type of general arguments in order to satisfy the signatures of all its methods.
source share