通过在Linq中使用匿名类型进行分组

时间:2017-01-02 13:51:55

标签: c# .net linq

假设我有一个Employee类,GetAllEmployees()返回一个employee实例列表。我想按部门和性别对员工进行分组,所以我的答案是

var employeeGroup = Employee.GetAllEmployees()
                            .GroupBy(x => new { x.Department, x.Gender }) // I don't understand this anonymous type
                            .OrderBy(g => g.Key.Department)
                            .ThenBy(g => g.Key.Gender)
                            .Select(g => new {   //I can understand this anonymous type
                               Dept = g.Key.Department,
                               Gender = g.Key.Gender,
                               Employees = g.OrderBy(x => x.Name)
                             });

我有两个问题:

  1. 为什么匿名类型允许使用多个密钥组?

  2. 我不理解第一个匿名类型,因为根据我的理解,匿名类型的格式应该是这样的

    new {field1 = x.Department,field2 = x.Gender}

  3. 为什么第一个匿名类型没有字段?我的意思是,写这样的东西是正确的语法:

    var anonymous = new {field1 = 1,field2 =2}
    

    但如果我这样写,会出现编译错误:

    var anonymous = new {1, 2} //compile error !!!
    

1 个答案:

答案 0 :(得分:17)

此处可以使用匿名类型按多个字段进行分组,因为GroupBy使用默认的相等比较器。 匿名类型的默认相等比较器对匿名类型的每个属性使用默认的相等比较器。

因此,对于第一个匿名类型,如果Department和两个Gender s相等(根据它们的默认相等比较器),则两个实例相等。

你可以想象匿名类型是这样的:

public class AnonymousType1
{
    public int Department { get; set; } // I don't know your department type
    public int Gender { get; set; } // neither your gender type

    public int GetHashCode() { return Department.GetHashCode() ^ Gender.GetHashCode(); }
    public bool Equals(AnonymousType1 other)
    {
        if (ReferenceEquals(other, null)) return false;
        return Department == other.Department && Gender == other.Gender;
    }
}

第二个问题也很简单:编译器使用属性名称(Department中的x.DepartmentGender中的x.Gender)作为匿名属性的名称类型。

所以

var anon = new { employee.Department, employee.Gender }

创建一个名为Department的属性和名为Gender的属性的类型 当然,这只适用于现有的属性/名称,而不能使用像

这样的常量值
var anon = new {1,2}; // fails to compile, no names provided.