6

ほとんどの人は、IComparable<T> を実装する参照型 (クラス) を記述するときに、null は実際のオブジェクトよりも小さいという規則を使用します。しかし、逆の規則を使用しようとすると、興味深いことが起こります。

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");
    }
  }
}

上記のコードを実行すると、null 参照が期待どおりにソートされていないことがわかります。どうやら、A と B を比較するときに、A がオブジェクトで B が null の場合、ユーザー定義の比較が使用されますが、逆に A が null で B がオブジェクトの場合は、代わりに何らかの BCL 比較が使用されます。

これはバグですか?

4

4 に答える 4

9

いいえ、これはバグではありません。実装するCompareToメソッドIComparable<Child>はクラスで定義されますChild。つまり、比較を行うために、型の 1 つでメソッドを呼び出す必要がある場合です。

比較対象の項目の 1 つChildが null の場合、どのように呼び出すことができますCompareToか?

IComparableの定義から次のことに注意してください。

「定義上、任意のオブジェクトは null 参照 (Visual Basic では Nothing) よりも大きい (またはそれに続く) 比較を行い、2 つの null 参照は互いに等しいと比較されます。」

これは、観察した結果を説明しています。

解決策は、他のクラスに委譲して比較を実行することです。IComparerインターフェイスを参照してください。

于 2011-05-31T15:20:38.637 に答える
1

が であるかどうかを評価しようとすると、何が起こると予想されますthis.Age.CompareTo(other.Age);か? 実際、C#には決してあり得ません。thisnullthisnull

バグかどうかについては、このブログ投稿を参照してください。

于 2011-05-31T15:21:38.857 に答える
1

Comparer<T>型のデフォルトTは、最初の要素 (A としましょう) が であるシナリオを考慮に入れる必要がありますnull。次のように見えるとしましょう。

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

return a.CompareTo(b);

これは、次のドキュメントにList<T>.Sort基づいています。

このメソッドは、 Comparer(Of T).Default型 T の既定の比較子を使用して、リスト要素の順序を決定します。

ほぼ間違いなく、両方の要素がである0場合にのみトップ ステップを返すことができ、それ以外の場合は の反対を使用できます。nullb.CompareTo(a)

しかし、私はそれを本当にバグとは呼びません。それは知っておくべきことです。

于 2011-05-31T15:24:20.250 に答える
1

いいえ、定義する標準に従っていないため、「バグ」があるコードですIComparable.CompareTo()IComparable

具体的には次のとおりです。 定義により、任意のオブジェクトはより大きい (または従う)nullと比較され、2 つのnull参照は互いに等しいと比較されます。

あなたの例では、オブジェクトを比較するように定義していますがnull、これは実行方法とは正反対です。

于 2011-05-31T15:24:20.273 に答える