Этот код возвращает различные значения. Однако я хочу вернуть строго типизированную коллекцию, а не анонимный тип

У меня есть следующий код:

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.

Ответ 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
               });