How GroupBy works

Good day to all! Please help me understand how GroupBy works and what is the difference in the code below.

class Employee {
    public string Name { get; set; }
    public string Id { get; set; }
    public string OfficeId { get; set; }
}

class Person {
    public string Name { get; set; }
    public string Id { get; set; }
}

class Program {
    static void Main(string[] args) {
        List<Employee> Employee = new List<Employee>() {
            new Employee { Id = "1", Name = "Alex", OfficeId = "1" },
            new Employee { Id = "2", Name = "John", OfficeId = "1" },
            new Employee { Id = "1", Name = "Alex", OfficeId = "2" },
            new Employee { Id = "2", Name = "John", OfficeId = "2" },
            new Employee { Id = "2", Name = "John", OfficeId = "3" },
        };

        var result1 = Employee.GroupBy(p => new { p.Id, p.Name });
        var result2 = Employee.GroupBy(p => new Person { Id = p.Id, Name = p.Name });
    }
}

In the case of result1, a collection with a similar type IEnumerable<IGrouping<AnonymousType<string, string>, Employee>> is created, where there are records with the keys Id and Name. The element where Id = "1", Name = "Alex" has two entries, the element where Id = "2", Name = "John" has three entries, respectively.

Here I have no particular questions and the structure of the object is the same as I expected it to be, but I needed to pass this object to the method as an argument, and I created the Person class to replace the anonymous type.

In result2, a collection is created like this collection IEnumerable<IGrouping<Person, Employee>> and I can explicitly specify the type that the method should accept. The problem is that here a list was created with five elements (keys) and each element has one value, which I did not expect and can not understand why this happens.

I will be grateful if they explain why there is such a difference results, if instead of an anonymous type in GroupBy, specify a custom type and how to do it to get an object with a data structure like in result1, but specifying a custom type.

P.S. If you specify grouping by one field in GroupBy (for example, Id), the result will be that in result1 only the key will consist of a string, but what about when the key should be an object with several properties?

Author: Alexander Petrov, 2019-06-04

1 answers

For anonymous types, the compiler automatically generates methods Equals and GetHashCode that:

Defined via the Equals and GetHashCode property methods, two instances of the same anonymous type are equal only if their properties are equal.

Quote from here: Anonymous Types (C Programming Guide#)

So the following code will output True:

var x = new { Id = 1, Name = "Ivan" };
var y = new { Id = 1, Name = "Ivan" };
Console.WriteLine(x.Equals(y));

In the Person class, the Equals method is not overridden, so it is used an implementation from the base class Object that compares references.

References to different instances are not equal, of course, so this code will return False:

var x = new Person { Id = 1, Name = "Ivan" };
var y = new Person { Id = 1, Name = "Ivan" };
Console.WriteLine(x.Equals(y));

Thus, grouping in the second case will create a separate group for each instance of Person.

 3
Author: Андрей NOP, 2019-06-04 20:02:37