在GroupBy中使用函数表达式作为参数

本文关键字:表达式 参数 函数 GroupBy | 更新日期: 2023-09-27 18:03:43

我正在创建一些统计数据,显示来自不同部门的多少员工是特定Active Directory组的成员。为此,我从ad中检索所有组成员,并按部门/组织级别对其进行分组。

我希望结果看起来像这样:

Org0 | Org1 | Org2 | Count
CFO  |      |      | 27
CFO  | AA   |      | 11
CFO  | AA   | JJ   | 11
CFO  | BB   |      | 16
CFO  | BB   | CC   |  4
CFO  | BB   | DD   | 12

我有一个类OrgUnit,它有以下成员:

public int Employees { get; set; }
public int Consultants { get; set; }
[NotMapped]
public int Total => Employees + Consultants;
public string Org0 { get; set; }
public string Org1 { get; set; }
public string Org2 { get; set; }

我还有一个Person类,它是派生的AD User对象,它包含成员Org0、Org1和Org2。

要获得每个组织单位/级别中有多少员工的计数,我使用GroupBy,问题是我无法弄清楚如何通过表达式使用通用组,因此我需要为每个组织级别提供一个方法。如下所示:

private static IEnumerable<T> GetLevel0<T>(IEnumerable<Person> persons) where T : OrgUnit, new()
{
    var level0 = persons.Where(x => !string.IsNullOrEmpty(x.Org0))
        .GroupBy(ac => new
        {
            ac.Org0
        })
        .Select(ac =>
        {
            return new T
            {
                Org0 = ac.Key.Org0,
                Consultants = ac.Count(x => x.EmpGroup.Equals("Consultant")),
                Employees = ac.Count(x => x.EmpGroup.Equals("Employee"))
            };
        });
    return level0;
}
private static IEnumerable<T> GetLevel1<T>(IEnumerable<Person> persons) where T : OrgUnit, new()
{
    var level1 = persons.Where(x => !string.IsNullOrEmpty(x.Org1))
        .GroupBy(ac => new
        {
            ac.Org0,
            ac.Org1
        })
        .Select(ac => new T
        {
            Org0 = ac.Key.Org0,
            Org1 = ac.Key.Org1,
            Consultants = ac.Count(x => x.EmpGroup.Equals("Consultant")),
            Employees = ac.Count(x => x.EmpGroup.Equals("Employee"))
        });
    return level1;
}

我的问题是,我怎么能使用泛型只有一个方法,而不是一个方法。

在GroupBy中使用函数表达式作为参数

你可以这样做,但需要一些合约,第一个合约是你知道有多少个参数列存在,并基于这个假设考虑元组元素的数量,在这个例子中,参数的数量是3:

Tuple的属性之一是相等性是由每个组件的默认对象相等比较器决定的。[MSDN]

如果你想要Level1,那么用新的Tuple.Create(p.Org0, null, null)填充组,如果想要Level2,那么组是Tuple.Create(p.Org0, p.Org1, null),等等。

public static IEnumerable<T> GetLevel<T>(IEnumerable<Person> persons, 
    Func<Person, Tuple<string, string, string>> group)
    where T : OrgUnit, new()
{
    var level1 = persons.Where(x => 
        !string.IsNullOrEmpty(group(x).Item2 == null ? group(x).Item1 :
        (group(x).Item3 ?? group(x).Item2)))
        .GroupBy(group)
        .Select(ac => new T
        {
            Org0 = ac.Key.Item1,
            Org1 = ac.Key.Item2,
            Org2 = ac.Key.Item3,
            Consultants = ac.Count(x => x.EmpGroup.Equals("Consultant")),
            Employees = ac.Count(x => x.EmpGroup.Equals("Employee"))
        });
    return level1;
}