【问题标题】:Expression Tree copying object表达式树复制对象
【发布时间】:2016-03-30 22:25:22
【问题描述】:

试图创建一个表达式树来做一个对象映射器类型的事情。

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 似乎看不到返回值...
  4. 我需要做块吗?还是有更好的方法?

【问题讨论】:

  • 返回的 lambda 需要为 Action&lt;Source, Dest&gt; 以便您传递两个对象,或者需要创建 Dest 并使用 Func&lt;Source,Dest&gt;。您当前正在为var2 定义一个局部变量,但从未构造(或传入)var2
  • @Rob -- 我想要 Func 结果,但编译器认为它仍然是一个动作,即使我有一个返回......我需要如何将代码修改为新的里面有 $var2 吗?

标签: c# tree expression


【解决方案1】:

你可以这样写:

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 

【讨论】:

  • 大声笑...是的,这很有效...比我尝试做的方式要容易得多。谢谢。
  • 非常感谢后续的生成、测试和实际结果部分,干杯
猜你喜欢
  • 2011-05-21
  • 2011-06-03
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多