Linq GroupBy具有动态属性的匿名类型

时间:2015-05-14 14:14:38

标签: c# linq anonymous-types

我正在尝试使用Linq对List<Person>进行分组。

var grouped = personList.GroupBy(x => new { x.Forename, x.Age })
                        .Select(x => new { Description = x.Key, Count = x.Count() });

如何使来自变量的属性成为变量?

var groupByProperties = new string[] { "Forename", "Age" };
personList.GroupBy(x => new { ............ })
          .Select(x => new { Description = x.Key, Count = x.Count() });

groupByProperties将来自网页上的用户输入(<select multiple>)。

我无法理解ExpandoObjectdynamic的正确语法,并且不确定我是否需要在此使用反射。

Person类可能类似于:

public class Person
{
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}

结果作为JSON传回UI(网页),从中生成数据网格。我将使用javascript循环返回的Description对象,并从中生成网格。

2 个答案:

答案 0 :(得分:1)

感谢potehin143指出我对ScottGu的优秀Linq Dynamic Query Library,我已经设法让一些东西在运行。

我最后得到了一个很好的单行(尽管有一些奇怪的语法)。

var fieldsToGroupBy = new string[] { "Forename", "Age" };

var grouped = personList.GroupBy( "new ( "+fieldsToGroupBy.ToCommaSeparatedString("it.")+" )", "it" )
                 .Select("new ( it.Key as Description, it.Count() as Count )");

response.Data = (dynamic)grouped;

ToCommaSeparatedString()是一种简单的扩展方法,可将[&#34; Forename&#34;,&#34; Age&#34;]更改为&#34; it.Forename,it.Age&#34;。

之前的解决方案(下面)并没有以我希望的格式返回数据。 (它在组中返回所有数据,而不仅仅是摘要。)感谢Mitsu提供此解决方案(博客文章herehere)。

var groupByProperties = new string[] { "Forename", "Age" };
var grouped = personList.GroupByMany(groupByProperties);

Linq动态查询库做得太多,甚至无法发布片段。 GroupByMany方法:

public static IEnumerable<GroupResult> GroupByMany<TElement>(
       this IEnumerable<TElement> elements, params string[] groupSelectors)
{
    var selectors =
        new List<Func<TElement, object>>(groupSelectors.Length);
    foreach (var selector in groupSelectors)
    {
        LambdaExpression l =
            DynamicExpression.ParseLambda(
                typeof(TElement), typeof(object), selector);
        selectors.Add((Func<TElement, object>)l.Compile());
    }
    return elements.GroupByMany(selectors.ToArray());
}

public static IEnumerable<GroupResult> GroupByMany<TElement>(
    this IEnumerable<TElement> elements,
    params Func<TElement, object>[] groupSelectors)
{
    if (groupSelectors.Length > 0)
    {
        var selector = groupSelectors.First();

        //reduce the list recursively until zero
        var nextSelectors = groupSelectors.Skip(1).ToArray();
        return
            elements.GroupBy(selector).Select(
                g => new GroupResult
                {
                    Key = g.Key,
                    Count = g.Count(),
                    Items = g,
                    SubGroups = g.GroupByMany(nextSelectors)
                });
    }
    else
        return null;
}

答案 1 :(得分:-1)

试试这个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication29
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Person> personList = new List<Person>();
            string[] groups = { "Forename", "Surname" };
            var grouped = personList.GroupBy(x => new object[] { Grouper(x, groups) })
                        .Select(x => new { Description = x.Key, Count = x.Count() });
        }
        static object[] Grouper(Person person, string[] groups)
        {
            List<object> results = new List<object>();
            foreach (string group in groups)
            {
                switch (group)
                {
                    case "Forename" :
                        results.Add(person.Forename);
                        break;
                    case "Surname":
                        results.Add(person.Surname);
                        break;
                    case "Age":
                        results.Add(person.Age);
                        break;
                    case "Gender":
                        results.Add(person.Gender);
                        break;
                }
            }


            return results.ToArray();
        }
    }
    public class Person
    {
        public string Forename { get; set; }
        public string Surname { get; set; }
        public int Age { get; set; }
        public string Gender { get; set; }
    }
}