私は分散の経験がほとんどありませんが、かなりの量を読んだ後、少なくとも基本的な概念を理解していると信じています (つまり、分散は、2 つのタイプの関係と、同様に投影された 2 つのタイプの関係の関係を表します)。IComparable<T>
しかし、反変として定義したことの意義や利点を理解できないようです。一見すると、これは実際にはサブタイプ間の比較可能性を妨げているように見えます。誰かがこの問題に光を当てることができることを願っています。
1 に答える
最初に取り組みますIComparer<T>
- あなたの質問には記載されていませんが、「販売」が少し簡単になり、IComparable<T>
.
次の 3 つのクラスがあるとします。
- 形状 (Area プロパティを持つ)
- サークル : 形
- 正方形 : 形状
を書くのは簡単AreaComparer : IComparer<Shape>
です。
( などの) は に変換できるList<Circle>
ため、反変性を使用すると、領域ごとに並べ替えることができます。IComparer<Shape>
AreaComparer
IComparer<Circle>
同様にIComparable<T>
-Shape
自体がIComparable<Shape>
を使用していると宣言した場合、各円はそれ自体を形状として比較できるためArea
、再び a を並べ替えることができます。List<Circle>
Circle
からへの暗黙的な変換があるため、多くの場合、これは実際には問題になりませんShape
。しかし、aCircle
が an と見なされる自然な能力は、IComparable<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
本当にコンパイラに満足してもらいたいのですが、これは aが共分散を介し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);
}
}
興味深いことに、ここでは型推論が機能しませんが、その理由はわかりません。ただし、反変性自体は問題ありません。