gpt4 book ai didi

c# - CoVariance 和 ContraVariance 中的类型安全

转载 作者:太空狗 更新时间:2023-10-29 17:40:07 27 4
gpt4 key购买 nike

我正在阅读 Jon Skeet 的《深入了解 C#》。虽然我已经理解了 CoVariance 和 ContraVariance 的概念,但是我无法理解这一行:

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# In Depth .

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

Covariance and ContraVariance

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>接口(interface)可能是最常见的协变示例。它是安全的,因为它只返回 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

Action<in T> delegate 是逆变的一个很好的例子。

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

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

逆变可以让你做这样的事情:

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 的实例.

关于c# - CoVariance 和 ContraVariance 中的类型安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30316008/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com