2016-03-30 39 views
1

嘗試創建表達式樹來執行對象映射器類型的事情。表達式樹複製對象

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. 我需要做塊嗎?或者,還有更好的方法?
+0

返回的lambda需要是'Func ',以便傳遞兩個對象或需要創建'Dest'。你目前爲'var2'定義了一個局部變量,但是'var2'永遠不會構造(或者傳入) – Rob

+0

@Rob - 我想要Func 結果,但編譯器認爲它仍然是一個Action儘管我有一個回報...我需要如何修改代碼以新增$ var2裏面? – SledgeHammer

回答

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 
+1

LOL ...是的,這樣做... ...更容易,然後我試圖做到這一點。謝謝。 – SledgeHammer

+1

我真的很感激後續章節的產生,測試和實際結果,歡呼聲 –