1
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.

Murdock
  • 4,352
  • 3
  • 34
  • 63

2 Answers2

4

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.

A Lazy<T> has no relationship with a Lazy<Control>, just as little as a Lazy<Base> has any relationship with Lazy<Derived>.

Just because Derived derives from Base and you can do this:

Base b = new Derived();

...it doesn't mean that you can do this:

Lazy<Base> b = new Lazy<Derived>();

The type Lazy<Derived> does not derive from Lazy<Base>. @Jon Skeet explains this well here:

C# variance problem: Assigning List<Derived> as List<Base>

mm8
  • 163,881
  • 10
  • 57
  • 88
4

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.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194