Как создать анонимный объект как выражение LINQ - PullRequest
0 голосов
/ 18 октября 2018

Я хотел бы создать следующее лямбда-выражение, используя дерево выражений в C #:

var result = dataList.GroupBy(x => new { x.Prop1, x.Prop2 })

Как сделать анонимный тип с двумя свойствами в качестве выражения LINQ (lambdaExp)?

Это то, что я получил до сих пор:

IQueryable<GraphData> queryableData = graphDataList.AsQueryable();
ParameterExpression pe = Expression.Parameter(typeof(GraphData), "x");

Expression prop1 = Expression.PropertyOrField(pe, "Prop1");
Expression prop2 = Expression.PropertyOrField(pe, "Prop2");

var lambdaExp = Expression.Lambda<Func<GraphData, object>>( new { prop1, prop2 } , pe);     //doesn't compile

MethodCallExpression groupByCallExpression = Expression.Call(
    typeof(Queryable),
    "GroupBy",
    new Type[] { typeof(GraphData), typeof(object) }, 
    queryableData.Expression,
    lambdaExp);

IQueryable<GraphData> result = queryableData.Provider.CreateQuery<GraphData>(groupByCallExpression);

1 Ответ

0 голосов
/ 19 октября 2018

Когда вы пишете запросы linq и анонимные объекты, компилятор скрывает много волшебства, которое он делает для вас.В частности, для анонимных объектов создает новые типы для вас.Если этот тип где-то не существует, вам нужно будет создать тип вручную и использовать его вместо него.

Вы можете немного обмануть и заставить компилятор создать объект с этим типом и сохранить ссылку на этот тип,При этом вы можете сгенерировать необходимые выражения для создания экземпляра этого объекта.

Следует отметить, что созданные для вас анонимные объекты будут иметь конструкторы с параметрами в порядке определения, поэтому вам просто нужно вызвать этот конструктор.

var keyType = new { Prop1=default(string), Prop2=default(string) }.GetType();
var ctor = keyType.GetConstructor(new Type[] { typeof(string), typeof(string) });
var param = Expression.Parameter(typeof(GraphData), "x");
var keySelector = Expression.Lambda(
    Expression.New(ctor,
        Expression.PropertyOrField(param, "Prop1"), // corresponds to Prop1
        Expression.PropertyOrField(param, "Prop2")  // corresponds to Prop2
    ),
    param
); // returns non-generic LambdaExpression

Имейте в виду, что мы имеем дело с типами, не известными во время компиляции, поэтому ваше выражение селектора ключа не будет иметь тип времени компиляции.

...