Объект в условии GROUP BY в C# LINQ - некорректная группировка, если использовать не анонимный тип

Есть тестовый список пользователей:

public class ClassForOrderBy
{
    public string Name { get;set; }
    public int Priority { get;set; }
    public long OwnerId { get;set; }
        
    public ClassForOrderBy(string name, int priority, int ownerId)
    {
        Name = name;
        Priority = priority;
        OwnerId = ownerId;
    }
}

List<ClassForOrderBy> t = new List<ClassForOrderBy>()
{
    new ClassForOrderBy("Иван",14,5),
    new ClassForOrderBy("Маша",27,6),
    new ClassForOrderBy("Маша",97,7),
    new ClassForOrderBy("Иван",60,8)
};

Так же есть тип для группировки (далее в этом типе будут добавляться свойства и заполняться по определенному условию, т.е. объект группировки будет меняться, остальные свойства будут null):

private class AdvancedGroupByFilter
{
    public string Name { get;set; }
    public AdvancedGroupByFilter(string name) => Name = name;
}

Необходимо сгруппировать элементы списка по свойству "Name". Для группировки я использую метод расширения LINQ (GroupBy), но он странно себя ведет:

  • если указать анонимный тип t.GroupBy(x => new {x.Name}), то мы получаем на выходе

введите сюда описание изображения

  • если указать тип BaseGroupByFilter t.GroupBy(x => new BaseGroupByFilter(x.Name)), то мы получаем на выходе

введите сюда описание изображения

Анонимные типы мне не подходят, так как далее будут дополнительные условие OrderBy и ThenBy, которые должны знать, объект какого типа использовался в GroupBy. Почему группировка так странно себя ведет и как заставить ее отрабатывать правильно при указании не анонимного типа?


Ответы (1 шт):

Автор решения: Andrew_1992

Публикую ответ на свой вопрос (возможно, кому-нибудь пригодится).

В комментарии к вопросу tym32167 был прав, когда рекомендовал переопределить методы Equals и GetHashCode. В результате имеем нечто следующее (дополнительно, для наглядности, добавил в тип BaseGroupByFilter свойство OwnerId с типом nullable long):

private class BaseGroupByFilter
{
    public string Name { get; }
    public long? OwnerId { get; }
    
    public BaseGroupByFilter(string name, long? ownerId = null)
    {
        Name = name;
        OwnerId = ownerId;
    }
    
    public override bool Equals(object obj) => Equals(obj as BaseGroupByFilter);

    public override int GetHashCode()
    {
        unchecked
        {
            var hash = (OwnerId != null ? OwnerId.GetHashCode() : 0);
            hash = (hash * 27) ^ Name.GetHashCode();
            return hash;
        }
    }

    private bool Equals(BaseGroupByFilter other) => 
        other != null && other.Name == this.Name && other.OwnerId == this.OwnerId;
}

Группировка теперь работает корректно:

введите сюда описание изображения

→ Ссылка