I ran across a typing situation while attempting to invoke a specific method overload, and now I'm curious: why does the following not induce a compilation error?
var a = (Task<Task>) (Task) null; // fine.
var b = (Func<Task<Task>>) (Func<Task>) null; // fine.
var c = (Task<Task<Task>>) (Task<Task>) null; // compilation error.
I would expect all of these examples to fail.
Error from the third line ( c
): Cannot cast expression of type 'System.Threading.Tasks.Task<System.Threading.Tasks.Task>' to type 'Task<Task<Task>>'
Your first line is sort of like doing (int) (object) 1
, which is perfectly legal because everything (including int
) derives from Object
.
Your second line is the same thing with contravariance in action.
The third line fails because the T
parameter of Task<T>
is not set up for covariance (and indeed, it cannot be because Task<T>
is a class, not an interface or delegate). It works for Func<TResult>
because Func<TResult>
is set up for covariance (ie, it's declared as Func<out TResult>
). Tasks may have been designed to disallow this on purposes, or they forgot to do it.
This is an extrapolation of Michael's answer :
For a
: Task<T>
derives from Task
, so this is OK.
For b
: Func
is a delegate with covariance, and therefore is implicitly converting Task
to Task<T>
on our behalf. Func
is unaltered, and therefore this is OK.
For c
: Task
cannot use covariant type arguments since it is a class, and Task<Task<T>>
does not derive from Task<T>
, therefore this is NOT OK.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.