2016-03-30 9 views
1

Versuch, einen Ausdrucksbaum zu erstellen, um eine Objekt-Mapper-Art zu tun.Expression Tree-Kopierobjekt

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); 

Also das ist, was ich jetzt habe ... seine ganz in der Nähe, aber nicht sehen, was mir fehlt ...

v kommt auf:

.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. Muss ich $ var2 irgendwo neu aufbauen?
  2. Gibt es eine bessere Möglichkeit, die Zuweisungen zu tun?
  3. Der Lambda scheint nicht den Rückgabewert zu sehen ...
  4. Muss ich den Block tun? oder gibt es einen besseren Weg?
+0

Entweder muss das zurückgegebene Lambda 'Func ' sein, damit Sie zwei Objekte übergeben, oder 'Dest' muss erstellt werden. Sie definieren gerade eine lokale Variable für 'var2', aber' var2' wird niemals konstruiert (oder übergeben) – Rob

+0

@Rob - Ich möchte das Func -Ergebnis, aber der Compiler denkt, es ist immer noch eine Aktion obwohl ich eine Rückkehr habe ... wie muss ich den Code zu neuen up $ var2 innerhalb ändern? – SledgeHammer

Antwort

4

Sie können so etwas schreiben:

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); 

Welche der folgenden generiert:

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

und -prüfung es:

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

ergibt sich ein Objekt von Dest:

A 5 
B TEST 
+1

LOL ... Ja, das funktioniert ... viel einfacher als die Art, wie ich es versuchte. Vielen Dank. – SledgeHammer

+1

Ich schätze wirklich die folgenden Abschnitte über Erzeugung, Prüfung und tatsächliche Ergebnisse, Cheers –