表达式树复制对象

Expression Tree copying object

正在尝试创建表达式树来执行对象映射器类型的操作。

Type ts = typeof(Source);
Type td = typeof(Dest);

ParameterExpression val = Expression.Parameter(ts);
ParameterExpression ret = Expression.Parameter(td);

PropertyInfo[] propsS = ts.GetProperties();
PropertyInfo[] propsD = td.GetProperties();

List<Expression> lst = new List<Expression>();

foreach (PropertyInfo pi in propsS)
{
    PropertyInfo piD = propsD.Where(x => x.Name == pi.Name).FirstOrDefault();

    if (piD != null)
    {
        MethodInfo ge = pi.GetGetMethod();
        MethodInfo se = piD.GetSetMethod();
        var v1 = Expression.Call(val, ge);
        var v2 = Expression.Call(ret, se, v1);
        lst.Add(v2);
    }
}

lst.Add(Expression.Return(Expression.Label(td), ret));

BlockExpression block = Expression.Block(
        new[] { ret },
        lst.ToArray()
    );

//Func<Source, Dest> v = Expression.Lambda<Func<Source, Dest>>(block, val).Compile();
var v = Expression.Lambda(block, val);

这就是我现在拥有的...它非常接近,但看不出我缺少什么...

v 结果:

.Lambda #Lambda1<System.Action`1[ConsoleApplication2.Source]>(ConsoleApplication2.Source $var1) {
    .Block(ConsoleApplication2.Dest $var2) {
        .Call $var2.set_S1(.Call $var1.get_S1());
        .Call $var2.set_S2(.Call $var1.get_S2());
        .Call $var2.set_I1(.Call $var1.get_I1());
        .Call $var2.set_I2(.Call $var1.get_I2());
        .Call $var2.set_S3(.Call $var1.get_S3());
        .Call $var2.set_S4(.Call $var1.get_S4());
        .Call $var2.set_S5(.Call $var1.get_S5());
        .Return #Label1 { $var2 }
    }
}
  1. 我需要在某个地方新建 $var2 吗?
  2. 有没有更好的分配方法?
  3. lambda 似乎没有看到 return 值...
  4. 我需要做块吗?或者有更好的方法吗?

你可以这样写:

Type sourceType = typeof(Source);
ParameterExpression source = Expression.Parameter(sourceType);

var createModel = Expression.New(typeof(Dest));
var bindings = new List<MemberAssignment>();
foreach (var prop in sourceType.GetProperties())
{
    var v1 = Expression.Call(source, prop.GetGetMethod());
    var destinationProperty = typeof(Dest).GetProperty(prop.Name);

    bindings.Add(Expression.Bind(destinationProperty, v1));
}
var init = Expression.MemberInit(createModel, bindings);

var lambdaExpression = Expression.Lambda<Func<Source, Dest>>(init, source);

这将生成以下内容:

Param_0 => new Dest() 
{
    A = Param_0.get_A(), 
    B = Param_0.get_B()
}

并对其进行测试:

var s = new Source { A = 5, B = "TEST" };
var res = lambdaExpression.Compile()(s);

产生一个对象 Dest:

A    5   
B    TEST