Search code examples
c#linqgrouping

GroupBy not working in .NET Core - same count in original and grouped list


I'm working on project in .NET Core 3.1, but the version is not relevant for this question because I have a problem with group by with simple examples.

My original query is long, so when I was in process of creating the query, I wrote models which I used later in select and group-by for example:

public class GroupClass 
{ 
    public int PropA { get; set; }
}

I thought that problem is with joining results, but even a simple example with this model is not working:

int[] testArray = { 1, 2, 3, 3, 3, 3, 3, 3 };
var result = (from a in testArray
              group a by new GroupClass
              {
                  PropA = a,
              } into g
              select new ModelClass
              {
                  PropA = g.Key.PropA,
              }).ToList();
Console.WriteLine(result.Count);
Result: 8 
Expected/wanted result: 3

Obviously, group-by failed to compare 3==3, but what should I do? I have same problem with fluent syntax.

Here is the full code on rextester: example.


Solution

  • The Problem is that Equals and GetHashCode are not defined (by default Equals compares memory locations). One way to make this work is to use anonymous object:

    group a by new
    {
       PropA = a,
    } into g
    

    This works because CLR creates those methods for you, as stated in documentation

    Because the Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashCode methods of the properties, two instances of the same anonymous type are equal only if all their properties are equal.

    Now to make it work with the model for group-by, you should implement Equals and GetHashCode:

    public class GroupClass
    {
        public int PropA { get; set; }
        
        public override bool Equals(object o)
        {
            if (o == null || GetType() != o.GetType())
            {
                return false;
            }
            
            var other = o as GroupClassWorking;
            return this.PropA == other.PropA;
        }
        
        public override int GetHashCode()
        {
            return PropA.GetHashCode();
        }
    }