等価性比較のカスタマイズ例として、HashSetでKeyValuePairを扱う例をみてみます。 次の例では、KeyValuePairからKeyの値を取得して比較を行うクラスKeyValuePairEqualityComparerを作成し、それをHashSetのコンストラクタに渡しています。 これによりKeyValuePair同士の比較ができるようになり、HashSetでKeyValuePairを扱うことができるようになります。

HashSetでKeyValuePairを扱う
using System;
using System.Collections.Generic;

// KeyValuePair<string, int>の等価性比較を行うIEqualityComparer<T>
class KeyValuePairEqualityComparer : EqualityComparer<KeyValuePair<string, int>> {
  public override bool Equals(KeyValuePair<string, int> x, KeyValuePair<string, int> y)
    => string.Equals(x.Key, y.Key); // KeyValuePairのKeyを比較する

  public override int GetHashCode(KeyValuePair<string, int> obj)
    => obj.Key.GetHashCode(); // KeyValuePairのKeyからハッシュ値を取得する
}

class Sample {
  static void Main()
  {
    var comparer = new KeyValuePairEqualityComparer();
    var s1 = new HashSet<KeyValuePair<string, int>>(comparer);

    s1.Add(KeyValuePair.Create("Dave", 1));
    s1.Add(KeyValuePair.Create("Alice", 2));
    s1.Add(KeyValuePair.Create("Alice", 99999));
    s1.Add(KeyValuePair.Create("Bob", 3));
    s1.Add(KeyValuePair.Create("Eve", 4));
    s1.Add(KeyValuePair.Create("Charlie", 5));

    Console.WriteLine(string.Join(", ", s1));

    var s2 = new HashSet<KeyValuePair<string, int>>(comparer);

    s2.Add(KeyValuePair.Create("Alice", 3));
    s2.Add(KeyValuePair.Create("Bob", 1));
    s2.Add(KeyValuePair.Create("Charlie", 2));

    Console.WriteLine(string.Join(", ", s2));

    // 差集合を求める
    Console.WriteLine("[ExceptWith]");

    s1.ExceptWith(s2);

    Console.WriteLine(string.Join(", ", s1));
  }
}
実行結果
[Dave, 1], [Alice, 2], [Bob, 3], [Eve, 4], [Charlie, 5]
[Alice, 3], [Bob, 1], [Charlie, 2]
[ExceptWith]
[Dave, 1], [Eve, 4]

この例のKeyValuePairEqualityComparerではKeyの値のみを比較しているため、Valueにどのような値が格納されているかといったことは一切考慮されません。 Keyの値が同一であれば、Valueの値に関わらず同一の要素とみなされます。