不使用MemberInit创建实例和集成员的表达式

时间:2018-03-15 06:55:42

标签: c# linq lambda expression

我需要创建一个实例并设置一些属性。通常我会使用Expression.MemberInit(Expression.New(type), memberBindings),但我需要通过调用自定义方法来创建实例。我无法弄清楚如何在实例表达式上设置成员。

我正在创建这样的实例。我实际上并没有使用Activator.CreateInstance,但它适用于此示例。

var method = typeof( Activator ).GetMethod( nameof( Activator.CreateInstance ), new Type[] { typeof( Type ) } );
Expression expression = Expression.Call( method, Expression.Constant( typeof( TestClass ) ) );

在我创建实例的表达式后,如何设置对象成员?

1 个答案:

答案 0 :(得分:3)

可以使用Expression.Block创建这样的表达式,但请注意,它只能用于编译lambda委托,因为除了LINQ to Objects之外的C#编译器和查询提供程序不支持表达式块

首先确保create instance方法返回正确的类型:

var method = typeof(Activator).GetMethod(nameof(Activator.CreateInstance), new Type[] { typeof(Type) });
var newObj = Expression.Convert(Expression.Call(method, Expression.Constant(typeof(TestClass))), typeof(TestClass));

并假设您已经有MemberAssignment个表达式列表,您通常会将其用于Expression.MemberInit

IEnumerable<MemberAssignment> memberBindings = ...;

然后可以按如下方式构建有问题的表达式:

var obj = Expression.Variable(newObj.Type, "obj");
var expressions = new List<Expression>();
expressions.Add(Expression.Assign(obj, newObj));
expressions.AddRange(memberBindings.Select(b => Expression.Assign(
    Expression.MakeMemberAccess(obj, b.Member), b.Expression)));
expressions.Add(obj);
var variables = new Expression[] { obj };
var result = Expression.Block(variables, expressions);

所以我们创建一个名为obj的变量,分配对象创建方法的结果,然后为每个成员绑定生成成员赋值,最后返回obj(块表达式中的最后一个表达式)列表)。

相关问题