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>
。我怀疑这比实际更麻烦值得。)
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>
。我怀疑这比实际更麻烦值得。)