by WebSurfer
2015年12月8日 19:44
IEnumerable<T> で T が匿名型の場合は Distinct() メソッドで期待通り重複のない結果が得られますが、T にカスタムデータ型を使った場合は、
-
そのカスタムデータ型に IEquatable<T> インターフェイスを継承させて Equals メソッドを実装し、GetHashCode メソッドを override する(具体例は MSDN ライブラリ Enumerable.Distinct<TSource> メソッド (IEnumerable<TSource>) のサンプルコード参照)、または、
-
IEqualityComparer<T> を継承したクラスを作成し、それを引数にとって値を比較できるバージョンの Distinct メソッドを使う(具体例は MSDN ライブラリ Enumerable.Distinct<TSource> メソッド (IEnumerable<TSource>, IEqualityComparer<TSource>) のサンプルコード参照)。
のいずれかの方法を取る必要があるそうです。知ってました? 実は自分は知らなかったです。匿名型を使っている限りは問題なかったので。(汗)
ちなみに、上に紹介した MSDN ライブラリのサンプルコードで、Product 型に替えて匿名型を使えば以下のように Distinct() メソッドを使って重複しない結果を取得できます。
var products = new[] {
new { Name = "apple", Code = 9 },
new { Name = "orange", Code = 4 },
new { Name = "apple", Code = 9 },
new { Name = "lemon", Code = 12 } };
var noduplicates = products.Distinct();
foreach (var product in noduplicates)
Console.WriteLine(product.Name + " " + product.Code);
/* 結果は:
apple 9
orange 4
lemon 12
*/
ただ、それで何故 Distinct() が使えるのかがズバリ書いてある Microsoft の公式文書が見つからないという不安はありますが。
一応、匿名型における Equals, GetHashCode, ToString メソッドおよび IEquatable<T> インターフェイスの実装について以下の文書があるのは見つけました。
上のコード new { Name = "apple", Code = 9 } で作られる匿名型にも上記が当てはまるのであろうとは思っていますが・・・
(注)VB.NET には Key というキーワードがあってそれを付与して定義したプロパティのみが比較の対象となるようです。一方、C# は上の記事にもあるように全てのプロパティが比較の対象になります。