Скажем, у меня есть этот класс:
public class Animal : IEquatable<Animal>
{
public string Name { get; set; }
public bool Equals(Animal other)
{
return Name.Equals(other.Name);
}
public override bool Equals(object obj)
{
return Equals((Animal)obj);
}
public override int GetHashCode()
{
return Name == null ? 0 : Name.GetHashCode();
}
}
Это тест:
var animals = new[] { new Animal { Name = "Fred" } };
Теперь, когда я это сделаю:
animals.ToList().Contains(new Animal { Name = "Fred" });
он вызывает правильную общую Equals
перегрузку. Проблема связана с типами массивов. Предположим, что я:
animals.Contains(new Animal { Name = "Fred" });
он вызывает не общий метод Equals
. Фактически T[]
не выставляет метод ICollection<T>.Contains
. В приведенном выше случае IEnumerable<Animal>.Contains
вызывается перегрузка расширения, которая в свою очередь вызывает ICollection<T>.Contains
. Вот как реализуется IEnumerable<T>.Contains
:
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); //this is where it gets done for arrays
}
return source.Contains(value, null);
}
Итак, мои вопросы:
- Почему
List<T>.Contains
иT[].Contains
ведут себя по-другому? Другими словами, почему бывшее имя вызывало общийEquals
, а последний не общийEquals
, хотя обе коллекции являются общими? - Есть ли способ, которым я вижу реализацию
T[].Contains
?
Изменить: Почему это имеет значение или почему я спрашиваю об этом:
-
Он запускается один раз, если она забывает переопределять не общие
Equals
при реализацииIEquatable<T>
, и в этом случае вызовы типаT[].Contains
выполняют проверку ссылочного равенства. Особенно, когда она ожидает, что все родовые коллекции будут работать с общимEquals
. -
Вы теряете все преимущества внедрения
IEquatable<T>
(даже если это не катастрофа для ссылочных типов). -
Как отмечено в комментариях, просто интересно знать внутренние детали и варианты дизайна. Нет другой общей ситуации, я могу подумать о том, где будет использоваться не общий
Equals
, будь то любые операцииList<T>
или set based (Dictionary<K,V>
и т.д.). Хуже того, имел Animal - это структура, Animal []. Содержит вызовы genericEquals
, все, что делает реализацию T [] странной, что разработчики должны знать,
Примечание. Общая версия Equals
вызывается только тогда, когда класс реализует IEquatable<T>
. Если класс не реализует IEquatable<T>
, негенерическая перегрузка Equals
вызывается независимо от того, вызывается ли она List<T>.Contains
или T[].Contains
.