分配给Lazy <>时的对比度/协方差问题

时间:2018-06-25 09:08:50

标签: c# covariance contravariance

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变量。

2 个答案:

答案 0 :(得分:4)

  

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

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>

答案 1 :(得分:3)

如果有一个ILazy<T>接口,则可以将其声明为ILazy<out T>,在您的示例中一切都会很好:T 有效地处于输出位置。

但是,Lazy<T>是一个类。只能为委托和接口指定协方差/协方差,因此Lazy<T>无法指定其协方差。

因此,Lazy<Control>Lazy<T>不兼容,这就是分配不起作用的原因。从调用者的角度来看,至少对于当前的API而言,协变是“安全的”。

(如果您到处都需要它,则可以声明自己的ILazy<out T>接口,然后编写该接口的实现来包装Lazy<T>。我怀疑这样做的麻烦多于其价值。 )