Этот код возвращает различные значения. Однако я хочу вернуть строго типизированную коллекцию, а не анонимный тип
У меня есть следующий код:
var foo = (from data in pivotedData.AsEnumerable()
select new
{
Group = data.Field<string>("Group_Number"),
Study = data.Field<string>("Study_Name")
}).Distinct();
Как и ожидалось, это возвращает различные значения. Однако я хочу вернуть строго типизированную коллекцию в отличие от анонимного типа, поэтому, когда я это сделаю:
var foo = (from data in pivotedData.AsEnumerable()
select new BarObject
{
Group = data.Field<string>("Group_Number"),
Study = data.Field<string>("Study_Name")
}).Distinct();
Это не возвращает отдельные значения, оно возвращает их все. Есть ли способ сделать это с помощью реальных объектов?
Ответы
Ответ 1
Чтобы работать Distinct()
(и многие другие функции LINQ), сравниваемый класс (BarObject
в вашем примере) должен реализовать реализацию Equals()
и GetHashCode()
или альтернативно предоставить отдельный IEqualityComparer<T>
как аргумент Distinct()
.
Многие методы LINQ используют преимущества GetHashCode()
для производительности, потому что изнутри они будут использовать вещи типа Set<T>
для хранения уникальных элементов, которые используют хэширование для поиска O (1). Кроме того, GetHashCode()
может быстро сказать вам, если два объекта могут быть эквивалентными, а какие - определенно нет - если GetHashCode()
правильно реализована.
Итак, вы должны сделать все свои классы, которые вы намерены сравнить в реализации LINQ Equals()
и GetHashCode()
для полноты, или создать отдельную реализацию IEqualityComparer<T>
.
Ответ 2
Вам нужно переопределить Equals
и GetHashCode
для BarObject
, потому что EqualityComparer.Default<BarObject>
является ссылочным равенством, если вы не предоставили переопределения Equals
и GetHashCode
(это то, что использует Enumerable.Distinct<BarObject>(this IEnumerable<BarObject> source)
). Кроме того, вы можете передать IEqualityComparer<BarObject>
в Enumerable.Distinct<BarObject>(this IEnumerable<BarObject>, IEqualityComparer<BarObject>)
.
Ответ 3
Либо сделайте так, как предложил или использовал dlev:
var foo = (from data in pivotedData.AsEnumerable()
select new BarObject
{
Group = data.Field<string>("Group_Number"),
Study = data.Field<string>("Study_Name")
}).GroupBy(x=>x.Group).Select(x=>x.FirstOrDefault())
Проверьте это для получения дополнительной информации http://blog.jordanterrell.com/post/LINQ-Distinct()-does-not-work-as-expected.aspx
Ответ 4
Похоже, Distinct
не может сравнивать ваши объекты BarObject
. Поэтому он сравнивает их ссылки, которые, конечно, все отличаются друг от друга, даже если они имеют одинаковое содержимое.
Таким образом, либо вы перезаписываете метод Equals
, либо поставляете собственный EqualityComparer до Distinct
. Не забывайте перезаписывать GetHashCode
при реализации Equals
, иначе это приведет к появлению странных результатов, если вы помещаете свои объекты, например, в словарь или хеш-таблицу в качестве ключа (например, HashSet<BarObject>
). Это может быть (не знаю точно), что Distinct внутренне использует hashset.
Здесь - это набор хороших практик для GetHashCode
.
Ответ 5
Вы хотите использовать другую перегрузку для Distinct(), которая принимает компаратор. Затем вы можете реализовать свой собственный IEqualityComparer <BarObject> .
Ответ 6
Попробуйте следующее:
var foo = (from data in pivotedData.AsEnumerable().Distinct()
select new BarObject
{
Group = data.Field<string>("Group_Number"),
Study = data.Field<string>("Study_Name")
});
Ответ 7
Должно быть так же просто, как:
var foo = (from data in pivotedData.AsEnumerable()
select new
{
Group = data.Field<string>("Group_Number"),
Study = data.Field<string>("Study_Name")
}).Distinct().Select(x => new BarObject {
Group = x.Group,
Study = x.Study
});