Скажем, у меня есть этот класс:
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.