c# – 在CoVariance和ContraVariance中输入安全性

我正在阅读Jon Skeet的深度C#.虽然我已经理解了协变量和对比变量的概念,但我无法理解这一行:

Well,covariance is safe when SomeType only describes operations that
return the type parameter—and contravariance is safe when SomeType
only describes operations that accept the type parameter.

有人可以用一个例子来解释两者,为什么两个都是一个方向的安全,而不是另一个方向?

Updated Question:

我仍然不明白答案.我将尝试使用与C#深度相同的例子来解释我的关注.

它解释了使用以下类层次结构:

COVARIANCE是:尝试转换IEnumerable< Circle>到IEnumerable< IShape>,但是提到这种转换是类型安全的,只有当我们在从某种方法返回时执行,而当我们将其作为IN参数传递时,这种转换不是类型安全的.

IEnumerable<IShape> GetShapes()
{
    IEnumerable<Circle> circles = GetEnumerableOfCircles();
    return circles; // Conversion from IEnumerable<Circle> to IEnumerable<IShape> - COVARIANCE
}

void SomeMethod()
{
    IEnumerable<Circle> circles = GetEnumerableOfCircles();
    DoSomethingWithShapes(circles); // Conversion from IEnumerable<Circle> to IEnumerable<IShape> - COVARIANCE
}

void DoSomethingWithShapes(IEnumerable<IShape> shapes) // Why this COVARIANCE is type unsafe??
{
    // do something with Shapes
}

CONTRA VARIANCE是:试图从IEnumerable< IShape>到IEnumerable< Circle>,其被提及为仅在作为IN参数发送时执行时被安全地类型安全.

IEnumerable<Circle> GetShapes()
{
    IEnumerable<IShape> shapes = GetEnumerableOfIShapes();
    return shapes; // Conversion from IEnumerable<IShape> to IEnumerable<Circle> - Contra-Variance
    // Why this Contra-Variance is type unsafe??
}

void SomeMethod()
{
    IEnumerable<IShape> shapes = GetEnumerableOfIShapes();
    DoSomethingWithCircles(shapes); // Conversion from IEnumerable<IShape> to IEnumerable<Circle> - Contra-Variance
}

void DoSomethingWithCircles(IEnumerable<Circle> circles) 
{
    // do something with Circles
}

解决方法

协方差

Covariance is safe when SomeType only describes operations that return the type parameter

IEnumerable< out T>界面可能是协方差最常见的例子.它是安全的,因为它只返回类型T的值(特别是IEnumerator< out T>但不接受任何T对象作为参数.

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

这是因为IEnumerator< T>也是共变的,只能返回T:

public interface IEnumerator<out T> : Idisposable,IEnumerator
{
    T Current { get; }
}

如果你有一个基类叫做Base,一个派生类叫Derived,你可以这样做:

IEnumerable<Derived> derivedItems = Something();
IEnumerable<Base> baseItems = derivedItems;

这是因为derivedItems中的每个项目也是Base的一个实例,因此我们完全可以按照我们刚才的方式进行分配.但是,我们不能指定另一种方式:

IEnumerable<Base> baseItems = Something();
IEnumerable<Derived> derivedItems = baseItems; // No good!

这不安全,因为不能保证Base的每个实例也是Derived的一个实例.

逆变

Contravariance is safe when SomeType only describes operations that accept the type parameter

动作< in T>代表是一个很好的例子.

public delegate void Action<in T>(T obj);

它是安全的,因为它只接受T作为参数,但不返回T.

Contravariance可以让你做这样的事情:

Action<Base> baseAction = b => b.DoSomething()
Action<Derived> derivedAction = baseAction;

Derived d = new Derived();
// These 2 lines do the same thing:
baseAction(d);
derivedAction(d);

这是因为将Derived的实例传递给baseAction是完全可以接受的.但是,它不会相反的方式:

Action<Derived> derivedAction = d => d.DoSomething()
Action<Base> baseAction = derivedAction; // No good!

Base b = new Base();
baseAction(b);    // This is OK.
derivedAction(b); // This does not work because b may not be an instance of Derived!

这不安全,因为不能保证Base的实例也是Derived的一个实例.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...