配列に対してContains()を呼ぶとIEquatable.Equals()が使われない

Enumerable.Contains<T>()の実装は以下のようになっていて、sourceがICollection<T>を実装していたらICollection<T>.Contains()が呼ばれ、実装していなかったらEqualityComparer<TSource>.Defaultで比較される。EqualityComparer<TSource>.Defaultはsourceの要素がIEquatable<T>を実装していたらIEquatable<T>.Equals()で、実装していなかったらObject.Equals()で比較する。

public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)
{
    ICollection<TSource> collection = source as ICollection<TSource>;
    if (collection != null) return collection.Contains(value);
    return Contains<TSource>(source, value, null);
}

https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,d1530e4eed8b26b3

配列はICollection<T>を実装しているが、IEquatable<T>.Equals()ではなくObject.Equals()を使って比較する。そのため、以下のようにIEquatable<T>を実装しているのにObject.Equals()がオーバーライドされていないと変な結果になってしまう。ガイドラインに従ってきちんとオーバーライドしよう。

List<T>ICollection<T>を実装しているが、そのContains()の実装ではEqualityComparer<TSource>.Defaultで比較している。Enumerable.Repeat<T>()は単なるイテレータを返すのでICollection<T>を実装したオブジェクトではない。つまりどちらもsourceの要素がIEquatable<T>を実装していたらIEquatable<T>.Equals()で比較する。

https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,521b9f7129105e15

https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,e2850cfe2b0cc87f

IEquatableについて詳しくはこちら。

qiita.com


ところで、配列をGetType()するとSystem.Array型であると分かるが、ArrayクラスはジェネリクスではなくICollectionは実装しているもののICollection<T>は実装していないように見える。

https://referencesource.microsoft.com/#mscorlib/system/array.cs,156e066ecc4ccedf

docs.microsoft.com

MSDocsによると、ジェネリクス版のインターフェースの実装は実行時に使えるようになるらしい。難しい。

Single-dimensional arrays implement the System.Collections.Generic.IList, System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyList and System.Collections.Generic.IReadOnlyCollection generic interfaces. The implementations are provided to arrays at run time, and as a result, the generic interfaces do not appear in the declaration syntax for the Array class.

以下のStackOverflowが詳しい。

stackoverflow.com