2012-08-03 37 views
4

我對方差的經驗很少,但在閱讀了一段時間後,我相信至少理解了基本概念(即方差描述了兩種類型的關係和這兩種類型的關係類似的預測)之間的關係。但是,我似乎無法理解定義爲逆變的意義或好處。乍一看,這實際上似乎阻礙了子類型之間的可比性。我希望有人能夠對此事發表一些看法。IComparable <T>作爲逆變的好處?

回答

6

我會首先處理IComparer<T> - 在你的問題中沒有提到,但是這是一個稍微簡單的「銷售」,然後導致IComparable<T>

假設你有三類:

  • 形狀(有小區物業)
  • 圈:外形
  • 廣場:外形

可以很容易地編寫一個AreaComparer : IComparer<Shape>

逆變讓您排序List<Circle>面積,因爲IComparer<Shape>(如AreaComparer)可轉換爲IComparer<Circle>

同樣的IComparable<T> - 如果Shape自己宣佈自己IComparable<Shape>使用Area,然後再次你可以排序List<Circle>,因爲每個圓圈絕不會比自己的形狀。

現在很多時候這實際上並不是問題,因爲您將從CircleShape的隱式轉換。但是將Circle的自然能力視爲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 

我們真的希望編譯器很樂意與T=Circle,我建議 - 這是隻要有效CircleIComparable<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); 
    } 
} 

有趣的是,類型推斷在這裏工作 - 但我不知道爲什麼。反轉本身雖然很好。

+0

Jon,現在已經多次閱讀您的回覆,我認爲這實際上已經開始有意義了。謝謝! – blf 2012-08-03 13:17:32

+0

喬恩,看起來好像我過早接受了你的答案。仍然發現自己有問題,我花了一些時間來實施涉及擬議的Foo 示例的測試案例。它不會編譯錯誤,「類型'Testable.Shape'不能用作通用類型或方法'Testable.Test.Foo (System.IComparable ,T)'中的類型參數'T''。沒有從'Testable.Shape'到'Testable.ISomethingCircleImplements'的隱式引用轉換「 – blf 2012-08-09 13:13:28

+0

@blf:是的,但你不想在那T = Shape。你想要T = Circle,它只有在Circle實現'IComparable '時纔有效,它只通過反轉來實現。 – 2012-08-09 13:56:56