Почему использование анонимного типа работает и использование явного типа не в GroupBy? - PullRequest
7 голосов
/ 05 ноября 2011

У меня проблема с тем, что я хочу, чтобы тип группы был строго типизирован, но если я это сделаю, он не будет правильно группироваться.См. Код ниже ...

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication35
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Foo> foos = new List<Foo>();
            foos.Add(new Foo() { Key = "Test" });
            foos.Add(new Foo() { Key = "Test" });
            foos.Add(new Foo() { Key = "Test" });

            var groups = foos.GroupBy<Foo, dynamic>(entry => new
            {
                GroupKey = entry.Key
            });

            Console.WriteLine(groups.Count());

            groups = foos.GroupBy<Foo, dynamic>(entry => new GroupingKey()
            {
                GroupKey = entry.Key
            });

            Console.WriteLine(groups.Count());

        }

        public class Foo
        {
            public string Key { get; set; }
        }

        public class GroupingKey
        {
            public string GroupKey { get; set; }
        }
    } 
}

Выходные данные:

1
3
Press any key to continue . . .

Я ожидаю, что результат будет одинаковым независимо от использования явного типа или нет, т.е. должен быть толькогруппа из 3 предметов, а не 3 группы с 1 предметом.Что здесь происходит?

Обновление Я добавил IEqualityComparer, и он работает сейчас!См. Ниже:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication35
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Foo> foos = new List<Foo>();
            foos.Add(new Foo() { Key = "Test" });
            foos.Add(new Foo() { Key = "Test" });
            foos.Add(new Foo() { Key = "Test" });

            var groups = foos.GroupBy<Foo, dynamic>(entry => new //GroupingKey()
            {
                GroupKey = entry.Key
            });

            Console.WriteLine(groups.Count());

            groups = foos.GroupBy<Foo, GroupingKey>(entry => new GroupingKey()
            {
                GroupKey = entry.Key
            }, new GroupingKeyEqualityComparer());

            Console.WriteLine(groups.Count());

        }

        public class Foo
        {
            public string Key { get; set; }
        }

        public class GroupingKey
        {
            public string GroupKey { get; set; }              
        }

        public class GroupingKeyEqualityComparer : IEqualityComparer<GroupingKey>
        {
            #region IEqualityComparer<GroupingKey> Members

            public bool Equals(GroupingKey x, GroupingKey y)
            {
                return x.GroupKey == y.GroupKey;
            }

            public int GetHashCode(GroupingKey obj)
            {
                return obj.GroupKey.GetHashCode();
            }

            #endregion
        }
    } 
}

Вывод:

1
1
Press any key to continue . . .

Это в значительной степени подтверждает ответ, данный JaredPar!

1 Ответ

8 голосов
/ 05 ноября 2011

В первой версии вы создаете анонимный тип с единственным свойством с именем GroupKey.Анонимные типы в C # используют структурное равенство, поэтому равенство значений сводится к равенству ключей.Это приводит к их правильной группировке.

Во втором случае вы используете пользовательский тип с именем GroupingKey.Похоже, это использует стандартное или ссылочное равенство.Следовательно, ни один из примеров не считается равным и, следовательно, они попадают в разные группы.

...