我对方差的经验很少,但在阅读之后我相信至少我理解了基本概念(即方差描述了两种类型的关系和类似投射的这两种类型的关系)之间的关系.但是,我似乎无法掌握IComparable< T>的重要性和好处了.定义为逆变.乍一看,这实际上似乎阻碍了亚型之间的可比性.我希望有人能够对此事有所了解.
解决方法:
我将解决IComparer< T>首先 – 在你的问题中没有提到它,但它稍微容易“卖”然后导致IComparable< T>.
假设你有三个类:
> Shape(具有Area属性)
>圆形:形状
>方形:形状
编写AreaComparer很容易:IComparer< Shape>.
Contravariance允许您对List< Circle>进行排序.按区域,因为IComparer< Shape> (例如AreaComparer)可转换为IComparer< Circle>.
同样,对于IComparable< T> – 如果Shape本身宣称自己是IComparable< Shape>使用Area,然后您可以再次对List< Circle>进行排序.因为每个圆圈都可以与自身形状相媲美.
现在很多时候这实际上不会成为问题,因为你有从Circle到Shape的隐式转换.但圆圈的自然能力被视为IC Comparable< Circle>在泛型方法的类型推断方面可以提供帮助.例如,假设我们有:
void Foo<T>(IComparable<T> item1, T item2)
我们试着打电话
Foo(circle1, circle2);
我不知道编译器是否会(没有逆变)能够推断出T = Shape,这会起作用……但即使它可以,它也会失败:
void Foo<T>(IComparable<T> item1, T item2) where T : ISomethingCircleImplements
我们真的希望编译器对T = Circle感到满意,我建议 – 这只有在Circle是IComparable< Circle>时才有效.通过协方差.
编辑:这是一个工作的例子:
using System;
public abstract class Shape : IComparable<Shape>
{
public abstract double Area { get; }
public int CompareTo(Shape other)
{
return Area.CompareTo(other.Area);
}
}
public interface ISomethingCircleImplements {}
public class Circle : Shape, ISomethingCircleImplements
{
private readonly double radius;
public Circle(double radius)
{
this.radius = radius;
}
public override double Area { get { return radius * radius * Math.PI; } }
}
class Test
{
static void Foo<T>(IComparable<T> item1, T item2)
where T : ISomethingCircleImplements
{
Console.WriteLine(item1.CompareTo(item2));
}
static void Main()
{
Circle c1 = new Circle(10);
Circle c2 = new Circle(20);
Foo<Circle>(c1, c2);
}
}
有趣的是,类型推断在这里不起作用 – 但我不确定为什么.逆变本身很好.