Список <T> .Contains и T []. Содержит поведение по-разному
Скажем, у меня есть этот класс:
public class Animal : IEquatable
{
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.Contains
метод. В приведенном выше случаеIEnumerable.Contains
перегружается расширение, которое в свою очередь вызываетICollection.Contains
, Вот какIEnumerable.Contains
реализовано:
public static bool Contains(this IEnumerable source, TSource value)
{
ICollection collection = source as ICollection;
if (collection != null)
{
return collection.Contains(value); //this is where it gets done for arrays
}
return source.Contains(value, null);
}
Итак, мои вопросы:
ЗачемдолженList.Contains
а такжеT[].Contains
вести себя по-другому? Другими словами, почему бывший называетобщийEquals
ипоследний неуниверсальныйEquals
хотя обе коллекции являются общими?Есть ли способ, которым я могу видетьT[].Contains
реализация?Редактировать: Почему это важно или почему я спрашиваю это:
Это отключает один на тот случай, если она забудет переопределитьне общийEquals
при реализацииIEquatable
в этом случае звонки какT[].Contains
делает проверку ссылочного равенства. Особенно когда она ожидаетвсе общие коллекции работать науниверсальныйEquals
Вы теряете все преимущества реализацииIEquatable
(хотя это некатастрофа для справочных типов).
Как отмечается в комментариях, просто интересно знать внутренние детали и выбор дизайна. Там нет другой общей ситуации, я могу думать о том, гдене общийEquals
будет предпочтительным, будь то любойList
или установить на основе (Dictionary
и т. д.) операции. Еще хуже,Если Animal был структурой, Animal []. Содержит вызовыобщийEquals
Все, что делает реализацию T [] странным, то, что разработчики должны знать.
Замечания: Общая версияEquals
вызывается только когда классреализуетIEquatable
Если класс нереализоватьIEquatable
неуниверсальная перегрузкаEquals
называется независимо от того, называется ли онList.Contains
или же .T[].Contains