Всем доброго времени суток! Прошу помочь разобраться в том, как работает GroupBy и в чем разница приведенного ниже кода.
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 });
}
}
В случае с result1 создается коллекция с подобным типом IEnumerable<IGrouping<AnonymousType<string, string>, Employee>>
где имеются вде записи с ключами Id и Name. Элемент, где Id = "1", Name = "Alex" имеет две записи, элемент, где Id = "2", Name = "John" имеет соответственно три записи.
Здесь у меня особо вопросов нет и структура объекта такая, какой я и ожидал ее увидеть, но мне понадобилось данный объект передать в метод в качестве аргумента и я создал класс Person, чтобы он заменял анонимный тип.
В result2 создается коллекция примерно вот такая коллекция IEnumerable<IGrouping<Person, Employee>>
и я могу явно указать тип, который метод должен принимать. Проблема в том, что тут создался список с пятью элементами (ключами) и каждый элемент имеет по одному значению, чего я не ожидал и не могу понять почему так происходит.
Буду благодарен, если объяснят почему идет такая разница результатов, если вместо анонимного типа в GroupBy указать пользовательский тип и как сделать, чтобы получить объект с структурой данных как в result1, но с указанием пользовательского типа.
P.S. Если в GroupBy указать группировку по одному полю (например Id), то результат будет, что и в result1 только ключ будет состоять из строки, но как быть когда ключ должен представлять из себя объект с несколькими свойствами?
Для анонимных типов компилятор автоматически генерирует методы Equals
и GetHashCode
, которые:
определяются через методы Equals
и GetHashCode
свойств, два экземпляра одного и того же анонимного типа равны, только если равны их свойства.
цитата отсюда: Анонимные типы (Руководство по программированию в C#)
Поэтому следующий код выведет True
:
var x = new { Id = 1, Name = "Ivan" };
var y = new { Id = 1, Name = "Ivan" };
Console.WriteLine(x.Equals(y));
В классе же Person
метод Equals
не переопределен, поэтому используется реализация из базового класса Object
, которая сравнивает ссылки.
Ссылки на разные экземпляры, конечно, не равны, поэтому такой код вернет False
:
var x = new Person { Id = 1, Name = "Ivan" };
var y = new Person { Id = 1, Name = "Ivan" };
Console.WriteLine(x.Equals(y));
Таким образом, группировка во втором случае создаст отдельную группу для каждого экземпляра Person
.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть мое приложениекоторое работает, и вот в него добавлю механизм записи технической информации
Как отключить полосы прокрутки у FlowDocumentScrollViewer в WPF?
Есть двусвязный список который мне нужно отсортировать за O(n Log n) времяЯ бы хотел использовать merge sort, но я никак не могу сообразить, как это...