C# LINQ Distinct を自作クラスのコレクションで使う方法


自作のクラスを保持するコレクションに対し LINQ の Distinct を使う場合、IEquatableインターフェースを実装する必要があるってことで、いろいろハマったのでメモ。

自作のクラスがこんな感じだったとする


public class MyModel
{
        public string ItemID { get; set; }
        public string ItemName { get; set; }

        public MyModel(string ItemID, string ItemName)
        {
                this.ItemID = ItemID;
                this.ItemName = ItemName;
        }
}

List<MyModel> に対し Distinct をしても動かない


List<MyModel> myModels = new List<MyModel>();

//
// もろもろ過程を経て、myModel にデータが格納されていると過程して
//

myModels = myModels.Distinct().ToList(); // 重複削除は行われない

まー、動かないかなーって思ってたけど(例えば何をもって重複と判断するのか的な)、これを思った通りの動きにする場合、MyModelクラスに IEquatable インターフェースを実装する

実装の例

この IEquatable を実装する場合、GetHashCode を override することと、Equals メソッドを実装する必要があるようです(ソースについては後述)


public class MyModel : IEquatable<MyModel>
{
        public string ItemID { get; set; }
        public string ItemName { get; set; }

        public MyModel(string ItemID, string ItemName)
        {
                this.ItemID = ItemID;
                this.ItemName = ItemName;
        }

        public override int GetHashCode()
        {
                return this.ItemID.GetHashCode();
        }

        bool IEquatable<MyModel>.Equals(MyModel myModel)
        {
                if( myModel == null )
                        return false;
                return (this.ItemID == myModel.ItemID);
        }
}

こうすることで、期待通りの動きになった。

ソース

Microsoft Developer Network Enumerable.Distinct メソッド

既定の等値比較子 Default は、IEquatable ジェネリック インターフェイスを実装している型の値を比較するために使用されます。 カスタム データ型を比較するには、このインターフェイスを実装し、その型の GetHashCode メソッドと Equals メソッドを独自に用意する必要があります。