###疑問
カスタムクラスのシーケンスに対する Enumerable.Distinct<T> 拡張メソッドの挙動について、
既定の等値比較子による比較で "重複" とみなされない理由がわかりません。
###調査内容
下記公式サイトからの引用です。
MSDN:Enumerable.Distinct<TSource> メソッド (IEnumerable<TSource>)
既定の等値比較演算子 Default は、IEqualityComparer<T> ジェネリック インターフェイスを実装している型の値を比較するために使用されます。 カスタム データ型を比較するには、このインターフェイスを実装し、その型の GetHashCode メソッドと Equals メソッドを独自に用意する必要があります。
つまり IEqualityComparer<T> を実装しろ、ということです。
こう書いてあるのだからそうすべきだ、といってしまえばそれまでなのですが、
Distinct<T> の内部実装を覗くと次のようなコードが見つかります。
C#
1if (this.slots[i].hashCode == num && this.comparer.Equals(this.slots[i].value, value)) 2{ 3 return true; 4}
つまりハッシュコードが一致していることと、
既定の Comparer による等値比較が一致していることで
"重複" とみなしているということです。
###試してみたコード
というわけで以下のようなコードを試してみました。
単純な人物情報を表す Person クラスを作成し、
インスタンスが重複する要素を持つリストに対して Distinct<T> を使用しています。
途中、ハッシュコードによる比較や既定の等値比較演算子による比較をおこなっていますが、
どれも "一致" という結果となります。
これにも関わらず Distinct<T> 拡張メソッドによって "重複" とみなされない理由はなんでしょうか。
C#
1namespace LinqTest 2{ 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 var p1 = new Person() { Name = "田中 淳平", Date = new DateTime(2011, 5, 2) }; 12 var p2 = new Person() { Name = "鈴木 ほのか", Date = new DateTime(2014, 3, 24) }; 13 var p3 = new Person() { Name = "小池 哲司", Date = new DateTime(2002, 6, 13) }; 14 var people = new List<Person>() { p1, p2, p1, p3 }; 15 var comparer = EqualityComparer<Person>.Default; 16 17 if (people[0].GetHashCode() == people[2].GetHashCode()) Console.WriteLine("GetHashCode は一致。"); 18 if (comparer.Equals(people[0], people[2])) Console.WriteLine("既定の Comparer による等値比較は一致。"); 19 if (comparer.GetHashCode(people[0]) == comparer.GetHashCode(people[2])) Console.WriteLine("既定の Comparer による GetHashCode は一致。"); 20 21 foreach (var p in people) 22 { 23 Console.WriteLine(p.Name + " (" + p.GetHashCode() + ")"); 24 } 25 26 Console.WriteLine("重複要素を除外します。"); 27 var newPeople = people.Distinct(); 28 foreach (var p in people) 29 { 30 Console.WriteLine(p.Name + " (" + p.GetHashCode() + ")"); 31 } 32 33 Console.ReadKey(); 34 } 35 } 36}
C#
1namespace LinqTest 2{ 3 using System; 4 5 /// <summary> 6 /// 人物データを表します。 7 /// </summary> 8 public class Person 9 { 10 /// <summary> 11 /// 氏名を取得または設定します。 12 /// </summary> 13 public string Name { get; set; } 14 15 /// <summary> 16 /// 更新日付を取得または設定します。 17 /// </summary> 18 public DateTime Date { get; set; } 19 } 20} 21
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/08 00:22