Contra/Covariance 分配给 Lazy<> 时出现问题

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;
}

我在最后一行收到以下错误。

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

我知道 T 可以是更具体的类型,但我不明白为什么我不能将它分配给 Lazy 变量。

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>Lazy<Control> 没有任何关系,就像 Lazy<Base>Lazy<Derived>.

没有任何关系一样

仅仅因为 Derived 派生自 Base 而你可以这样做:

Base b = new Derived();

...这并不意味着你可以这样做:

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

类型 Lazy<Derived> 不是从 Lazy<Base> 派生的。 @Jon Skeet 在这里很好地解释了这一点:

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

如果有一个 ILazy<T> 接口,它可以声明为 ILazy<out T>,在你的例子中一切都会很好:T 只用在一个输出位置,有效。

然而,Lazy<T>是一个class。 Covariance/contravariance只能为委托和接口指定,所以Lazy<T>不能指定它的协方差。

因此 Lazy<Control>Lazy<T> 不兼容,这就是作业不起作用的原因。这绝对令人沮丧,因为至少在当前 API 的情况下,从调用者的角度来看,它是协变的 "safe"。

(如果你到处都需要这个,你可以声明自己的 ILazy<out T> 接口,然后编写该接口的实现来包装 Lazy<T>。我怀疑这比实际更麻烦值得。)