#c# #linq
#c# #linq
Вопрос:
Предположим, у меня есть класс с именем MyClass, который имеет два свойства (идентификатор int и строковое имя). Я хочу заполнить список этих объектов MyClass из другой коллекции, но мне нужны только уникальные. Эта другая коллекция является объектом третьей стороны, который имеет свойство с именем ‘Properties’, представляющее собой просто массив значений, первые два из которых соответствуют значениям Id и Name, которые меня интересуют. В этой коллекции могут быть дубликаты, поэтому мне нужны только уникальные.
Кажется, что это должно сработать, но это не так, он возвращает все элементы независимо от дубликатов. Что я здесь делаю не так?
List<MyClass> items = (from MyClass mc in collectionOfProps
select new MyClass() {
Id = collectionOfProps.Properties[0],
Name = collectionOfProps.Properties[1] }).Distinct().ToList();
Комментарии:
1. глядя на ваш запрос, мне он кажется хорошим.
Ответ №1:
Проблема, вероятно, в том, что MyClass
не реализуется IEquatable<MyClass>
так же хорошо, как переопределение Equals
и GetHashCode
.
Чтобы заставить Distinct()
работать так, как вы хотите, вы должны реализовать IEquatable<T>
. В противном случае для проверки используется значение по умолчанию (ссылочное равенство), что означает, что он определил бы, что элементы не различаются, только если бы они были одним и тем же экземпляром.
Комментарии:
1. Эта страница , кажется, объясняет, почему внедрение
IEquatable<MyClass>
не обязательно решит проблему само по себе.2. @Brian: Ему тоже нужно
GetHashCode()
.3. @SLaks: Да, но заполнение a
GetHashCode
вIEqualityComparer
также не поможет (очевидно, что его ввод в type поможет ). В любом случае, человек в этой статье пытался избежатьGetHashCode
и был вынужден поступить немного некрасиво, чтобы достичь своей цели.4. @Brian Обратите внимание, что, если вы читали документацию для
IEquatable<T>
, там явно упоминается, что вы всегда должны переопределятьEquals
иGetHashCode
при реализации интерфейса. «Правильная» реализацияIEquatable<T>
подразумевает, что вы реализуете все три, даже если в интерфейсе определен только один метод.5. @ReedCopsey: Вы правы. Кроме того, в документации для
Distinct
явно указано, что нужно реализоватьIEquatable
. Хотя более внимательное прочтение документации (т. Е. игнорирование краткого объяснения компаратора по умолчанию и вместо этого чтение связанной документации ) показывает, что достаточно переопределитьEquals
иGetHashCode
.
Ответ №2:
Вам нужно переопределить Equals()
и GetHashCode()
сравнить экземпляры по значению.
Комментарии:
1. SLaks верен. По крайней мере, в .Net 4.0,
Distinct
реализуется с использованием aSet
(internal
класс framework, который похож на aHashSet
).
Ответ №3:
Вы переопределили равенство (для distinct) в MyClass? Мое предположение было бы отрицательным.
Согласно документам:
http://msdn.microsoft.com/en-us/library/bb348436.aspx
Средство сравнения равенства по умолчанию, Default, используется для сравнения значений типов, которые реализуют универсальный интерфейс IEquatable (Of T). Чтобы сравнить пользовательский тип данных, вам необходимо реализовать этот интерфейс и предоставить свои собственные методы GetHashCode и Equals для этого типа.