2011-05-31 23 views
6

大多數人在編寫實現IComparable <T>的申請類型(類)時,使用null比任何實際對象都少的約定。但是,如果你嘗試使用相反的協定,一些有趣的事情發生了:排序其中一些爲空的IComparable對象

using System; 
using System.Collections.Generic; 

namespace SortingNulls 
{ 
    internal class Child : IComparable<Child> 
    { 
    public int Age; 
    public string Name; 

    public int CompareTo(Child other) 
    { 
     if (other == null) 
     return -1; // what's your problem? 

     return this.Age.CompareTo(other.Age); 
    } 

    public override string ToString() 
    { 
     return string.Format("{0} ({1} years)", this.Name, this.Age); 
    } 
    } 

    internal static class Program 
    { 
    private static void Main() 
    { 
     var listOfChilds = new List<Child> 
     { 
     null, 
     null, 
     null, 
     null, 
     new Child { Age = 5, Name = "Joe" }, 
     new Child { Age = 6, Name = "Sam" }, 
     new Child { Age = 3, Name = "Jude" }, 
     new Child { Age = 7, Name = "Mary" }, 
     null, 
     null, 
     null, 
     null, 
     new Child { Age = 7, Name = "Pete" }, 
     null, 
     new Child { Age = 3, Name = "Bob" }, 
     new Child { Age = 4, Name = "Tim" }, 
     null, 
     null, 
     }; 

     listOfChilds.Sort(); 

     Console.WriteLine("Sorted list begins here"); 
     for (int i = 0; i < listOfChilds.Count; ++i) 
     Console.WriteLine("{0,2}: {1}", i, listOfChilds[i]); 
     Console.WriteLine("Sorted list ends here"); 
    } 
    } 
} 

當運行上面的代碼,您會看到預期的空引用不排序。顯然,在比較A和B時,如果A是對象而B是null,則使用用戶定義的比較,但是如果相反地A是空且B是對象,則使用一些BCL比較來替代。

這是一個錯誤?

回答

8

不,這不是一個錯誤。實施IComparable<Child>CompareTo方法在您的Child類中定義。換句話說,如果您必須在您的某個類型上調用某個方法才能進行比較。

如果其中一個Child項目爲空,您如何調用CompareTo呢?

注意,從IComparable定義:

「根據定義,任何物體進行比較大於(或如下)一個空引用(Visual Basic中爲Nothing),和兩個空引用比較彼此相等。 「

這解釋了你觀察到的結果。

解決方案是委託給其他一些類來執行比較。請參閱IComparer界面。

+0

很好的答案。我沒有注意到文檔說一個對象必須比null大。 當A爲空且B不爲空時,框架*可以*交換A和B,稱爲我的方法,然後翻轉返回的Int32的符號。我認爲有時會發生在舊的非通用IComparable中。 當然,使用IComparer 或比較委託,很容易處理null作爲第一個參數。 – JeppeSN 2011-05-31 16:28:59

1

如果您試圖評估this.Age.CompareTo(other.Age);如果thisnull會發生什麼?實際上,在C#中,this永遠不可能是null

至於問是否是bug,請參閱this blog post

1

T類型的默認Comparer<T>必須考慮到第一個元素(我們稱之爲A)爲null的場景。比方說,它看起來是這樣的:

if (ReferenceEquals(a, null)) 
{ 
    return -1; 
} 

return a.CompareTo(b); 

這是基於the documentation of List<T>.Sort

此方法使用默認的比較 Comparer(Of T).Default T類型,以確定 列表元素的順序。

可以說,頂端步驟只能返回0如果兩個元件是null,和以其他方式使用的b.CompareTo(a)相反。但是,我不會真的稱之爲錯誤。這只是要注意的一點。

1

否,其代碼具有「錯誤」作爲其不以下定義IComparable.CompareTo()標準:IComparable

具體做法是:根據定義,任何物體比比較大(或如下)null,以及兩個null引用比較相等。

在你的例子中,你正在定義你的對象比較小於(或先於)null,這恰恰與它應該如何做相反。