Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning a concrete Task<TImplementation> to a variable of type Task<TInterface>

Consider a class Foo which wholly implements IFoo. Concurrently, consider a task Task<IFoo>.

Why is it that when the following is called, a compilation error is thrown;

Task<IFoo> task = Task.Factory.StartNew(() => new Foo());

The compiler states that it cannot convert from source type Task<Foo> to Task<IFoo>. While this makes sense because they are essentially two differing types, would it not fall under the same premise as IList<IFoo> list = new List<IFoo>{new Foo(/* construct */)};, or other similar assignments?

At the moment I am forcing a cast to the interface, but this feels unneccesary.

like image 331
Daniel Park Avatar asked Jan 09 '23 07:01

Daniel Park


1 Answers

That is because this statement Task.Factory.StartNew(() => new Foo()); returns an instance of type Task<Foo>.

And given that the Task<> class is a concrete class, it cannot be covariant, unless it were implementing a covariant interface (i.e. ITask<out T>).

Note that there is a uservoice topic to do just that: "Make Task implement covariant interface ITask".

Also note the following possible explanation on why it is the way is it now, "Lack of Covariance in the Task Class":

Framework guidelines are:

  • If your framework already includes an interface for other reasons, then by all means make it co+contravariant.
  • But don't introduce an interface solely for the purposes of enabling co+contravariance.

The justification is that the advantage of covariance is outweighed by the disadvantage of clutter (i.e. everyone would have to make a decision about whether to use Task<T> or ITask<T> in every single place in their code).

For now you will have to do:

Task<IFoo> task = Task.Factory.StartNew<IFoo>(() => new Foo());
like image 58
Alex Avatar answered Jan 16 '23 16:01

Alex