如何在表达式树中实例化和初始化动态对象?

Pav*_*nin 5 .net c# iqueryable dynamic expression-trees

IQuerayble<TItem>我们合作时,我们可以这样打电话Select:

query.Select( item => new { A=item.Prop1, B=item.Prop2});
Run Code Online (Sandbox Code Playgroud)

Select方法预期Expression<Func<TItem,TResult>>

我需要使用ExpandoObject而不是匿名但静态类型的类.

如果有可能,它看起来像:

query.Select( item => dynamic new ExpandoBoject { A=item.Prop1, B=item.Prop2});
Run Code Online (Sandbox Code Playgroud)

所以我想构建表达式树Expression<Func<TItem,ExpandoObject>>,其中对象的属性以与匿名类型类似的方式初始化.
只有初始化才需要动态功能,因此Func返回ExpandoObject而不是dynamic.

我找不到很多关于Expression.Dynamic我应该使用的文档和相应的粘合剂.


更新1

为什么我需要这些东西?
因为我想获得主键.
我想为任何实体类型做这件事.

我知道如何获得组成PK的属性列表,但现在我需要对实体做一个棘手的投影EntityKey.好吧,可能与这个班级相同.

var keys = context.Set<TEntity>().Where(Expression<Func<TEntity,bool>).Select(Expression<Func<TEntity,EntityKey>>);
Run Code Online (Sandbox Code Playgroud)

正如我在评论中指出的那样,包含块的lambdas无法转换为表达式树,所以我不能简单地创建字典并填充它.现在,我正在使用语义上接近此代码的表达式树:

var dict = new Dictionary<string,object>();
dict.Add("Prop1",value1);
dict.Add("Prop2",value2);
return dict
Run Code Online (Sandbox Code Playgroud)

但我怀疑EF可以解析包含块的表达式.需要检查.
我很好奇它是否适用于动态对象和Expression.MemberInit,因为它适用于静态对象.


更新2

实体框架不支持字典初始化语法.
它抛出NotSupportedException了以下消息:LINQ to Entities中仅支持具有单个元素的列表初始化项.


更新3

EF不支持块表达式.
NotSupportedExceptionwith message:'Block'类型的未知LINQ表达式.

svi*_*ick 4

现在我正在使用语义上与此代码接近的表达式树:

var dict = new Dictionary<string,object>();
dict.Add("Prop1",value1);
dict.Add("Prop2",value2);
return dict;
Run Code Online (Sandbox Code Playgroud)

可以这样做,因为您可以将该代码编写为单个表达式,如下所示:

new Dictionary<string, object>
{
    { "Prop1", value1 },
    { "Prop2", value2 }
};
Run Code Online (Sandbox Code Playgroud)

您可以创建一个包含此表达式(EF 应该能够处理)的表达式树,如下所示:

var addMethod = typeof(Dictionary<string, object>).GetMethod("Add");

var expression = Expression.Lambda<Func<Dictionary<string, object>>>(
    Expression.ListInit(
        Expression.New(typeof(Dictionary<string, object>)),
        Expression.ElementInit(
            addMethod,
            Expression.Constant("Prop1"),
            value1Expression),
        Expression.ElementInit(
            addMethod,
            Expression.Constant("Prop2"),
            value2Expression)),
    itemParameterExpression);
Run Code Online (Sandbox Code Playgroud)