おーみんブログ

C#, ASP.NET Core, Unityが大好きです。

IEquatable<T>インターフェースを用いて独自の等価比較を行う。

はじめに

IEquatableインターフェースを用いて独自の等価比較を行うサンプルを記載します。

docs.microsoft.com

通常の比較

通常クラスのインスタンスでは参照の等価比較が行われます。 参照の等価比較のため、例えば以下のプログラムでは結果は「0」になります。

public class Program
{
    static void Main()
    {
        var sample1List = new List<Sample>(){ new Sample { SampleId = 1, SampleText = "Test1" }};
        var sample2List = new List<Sample>(){ new Sample { SampleId = 1, SampleText = "Test1" }};
        var intersectList = sample1List.Intersect(sample2List).ToList();
        Console.WriteLine(intersectList.Count);
    }
}

public sealed class Sample
{
    public int SampleId { get; set; }
    public string SampleText { get; set; }
}

※Intersectメソッドは2つのシーケンスの積集合を生成します。

Enumerable.Intersect メソッド (System.Linq) | Microsoft Docs

IEquatableインターフェースを実装後の比較

独自の等価比較を行う場合は比較対象のクラスにIEquatable\インターフェースを実装し、Equalsメソッドへ独自の比較ロジックを記載します。 今回はSampleIdが等しい場合は同じインスタンスであるという定義にしています。 こちらを実行すると結果は「1」となります。

public class Program
{
    static void Main()
    {
        var sample1List = new List<Sample>(){ new Sample { SampleId = 1, SampleText = "Test1" }};
        var sample2List = new List<Sample>(){ new Sample { SampleId = 1, SampleText = "Test1" }};
        var intersectList = sample1List.Intersect(sample2List).ToList();
        Console.WriteLine(intersectList.Count);
    }
}

public sealed class Sample : IEquatable<Sample>
{
    public int SampleId { get; set; }
    public string SampleText { get; set; }

    public bool Equals(Sample other) 
    {
       if(other == null) return false;
       return SampleId == other.SampleId;  
    }

    public override bool Equals(object obj)
    {
        if(obj is Sample sample) return Equals(sample);
        return false;
    }

    public override int GetHashCode() => 0; 
}

※ちなみに上記のコードだとSampleIdだけで等価比較を行っているので、例えばSampleIdが1でSampleTextが"Test2"の場合も等価と見なされます。

おわりに

比較は色々と手法があるので覚えるのが大変ですが、しっかり使いこなしていきたいです。