Search code examples
c#covariancecontravariance

Contra/Covariance issue when assigning to Lazy<>


private void AMethod<T>() where T : Control, new()
{
    Lazy<T> lazyControl = new Lazy<T>(() => new T());

    Lazy<Control> a = lazyControl;
}

I get the following error on the last line.

Argument 2: cannot convert from 'System.Lazy<T>' to
'System.Lazy<System.Windows.Forms.Control>'

I get that T could be a more specific type, but I don't get why I can't assign it to the Lazy variable.


Solution

  • If there were an ILazy<T> interface, it could be declared as ILazy<out T>, and all would be well in your example: the T is only used in an output position, effectively.

    However, Lazy<T> is a class. Covariance/contravariance can only be specified for delegates and interfaces, so Lazy<T> can't specify its covariance.

    Therefore Lazy<Control> is incompatible with Lazy<T>, which is why the assignment isn't working. It's definitely frustrating, given that with the current API at least, it would be "safe" for it to be covariant, from a caller perspective.

    (If you need this all over the place, you could declare your own ILazy<out T> interface and then write an implementation of that interface to wrap a Lazy<T>. I suspect that's more trouble than it's worth though.)