Linq:根据变量分组结果不同(例如枚举)

Linq: Group by that groups results differently according to a variable (enum for example)

我正在尝试 运行 一个查询 其中 'GroupBy' 子句将根据说,一个将数据绑定到组合框等的枚举值对结果进行不同的分组.

我尝试使用 switch case 来做到这一点,但这导致了 'GroupBy' 子句上的编译器错误 CS0411,因为据我所知,从 lambda 返回的对象类型会有所不同,具体取决于在哪种情况下执行。

如何巧妙地实现这个功能?

我在下面附上了一个问题的最小示例,作为控制台程序。

class Program
{
    static List<Person> People;

    enum GroupBy
    {
        Month,
        Year
    }

    static void Main(string[] args)
    {            
        People = new List<Person>();

        People.Add(new Person()
        {
            Dob = new DateTime(2000,10,1),
            Name = "James",
            IsSelected = false               
        });
        People.Add(new Person()
        {
            Dob = new DateTime(2000, 5, 1),
            Name = "Anne",
            IsSelected = true
        });
        People.Add(new Person()
        {
            Dob = new DateTime(2000, 5, 23),
            Name = "Bob",
            IsSelected = true
        });
        People.Add(new Person()
        {
            Dob = new DateTime(1999, 1, 15),
            Name = "Kate",
            IsSelected = false
        });

        // Obviously, in the real thing, the grouping value would be
        // databound to a combobox or something.
        GroupBy grouping = GroupBy.Month;

        var groups = People
            .OrderBy(x => x.Dob)
            .GroupBy(x => /* PROBLEM LINE - Gives compiler error CS0411 */
            {
                switch(grouping)
                {
                    case GroupBy.Month:
                        return new { x.Dob.Year, x.Dob.Month };
                    case GroupBy.Year:
                        return new { x.Dob.Year};
                    default:
                        throw new Exception("No can do");
                }
            });

        Console.WriteLine("Grouping is: " + grouping + "\r\n");
        foreach(var group in groups)
        {
            Console.WriteLine("Group: " + group.Key);
            foreach(Person p in group)
            {
                Console.WriteLine("\t" + p.Name + ", " + p.Dob);
            }
            Console.WriteLine("");
       }

       Console.ReadKey();
           
    }
}

public class Person
{
    public DateTime Dob { get; set; }
    public string Name { get; set; }
    public bool IsSelected { get; set; }
}

问题出现在返回匿名类型时的 switch 语句中。编译器无法推断类型(因为它是由编译器为每个单独的投影生成的)并因此抛出错误。

您可以通过创建包装器轻松解决此问题 class:

public class GroupedResult
{
    public int Year { get; set; }
    public int Month { get; set; }
}
var groups = People
    .OrderBy(x => x.Dob)
    .GroupBy(x => /* PROBLEM LINE - Gives compiler error CS0411 */
    {
        switch (grouping)
        {
            case GroupBy.Month:
                return new GroupedResult { Year = x.Dob.Year, Month = x.Dob.Month };
            case GroupBy.Year:
                return new GroupedResult { Year = x.Dob.Year };
            default:
                throw new Exception("No can do");
        }
    });

OR 通过确保两个匿名类型上存在相同的属性,从而产生相同的 compiler-generated 类型:

var groups = People
    .OrderBy(x => x.Dob)
    .GroupBy(x => /* PROBLEM LINE - Gives compiler error CS0411 */
    {
        switch (grouping)
        {
            case GroupBy.Month:
                return new  { Year = x.Dob.Year, Month = x.Dob.Month };
            case GroupBy.Year:
                return new  { Year = x.Dob.Year, Month = 0 };
            default:
                throw new Exception("No can do");
        }
    });

最简单的解决方案:

.GroupBy(x => new 
{ 
    Year = x.Dob.Year, 
    Month = grouping == GroupBy.Month ? x.Dob.Month : 0 
};
  • Year 始终是您分组的一部分
  • 只有当 grouping 等于 Month 时,
  • Month 才会成为您分组的一部分
    • 否则使用常量<<因此不分组

我建议避免在 GroupBy 委托中抛出异常。

  • 宁愿做一个初步检查并提前退出。