2016-03-30 19 views
1

Nesne eşleme türünde bir şey yapmak için bir ifade ağacı oluşturmaya çalışıyor.İfade Ağacı kopyalama nesnesi

.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 } 
    } 
} 
    :

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

    Böylece

    v çıkar ... Şimdi ... onun çok yakın, ama ben eksik görmüyorum ne

  1. $ var2'yi bir yerlere yükseltmem gerekiyor mu?
  2. Atamaları yapmak için daha iyi bir yol var mı?
  3. Lambda dönüş değeri görünmüyor ...
  4. Bloğu yapmam gerekiyor mu? ya da daha iyi bir yolu var mı?
+0

Döndürülmüş lambda'nın "Func " olması gerekir, böylece iki nesneyi iletirsiniz veya "Dest" in oluşturulması gerekir. Şu anda var2 için yerel bir değişken tanımlıyorsunuz, ancak var2 hiçbir zaman – Rob

+0

@Rob olarak oluşturulmadı - Func sonucunu istiyorum, ancak derleyici hala bir Eylem olduğunu düşünüyor. bir geri dönüşüm olsa da ... kodu $ var2'nin içinde yenisiyle değiştirmek için nasıl değiştirmem gerekiyor? – SledgeHammer

cevap

4

Böyle bir şey yazabilirsiniz:

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

Ve onu test:

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

Dest bir nesne verir aşağıdaki üretecektir

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

:

A 5 
B TEST 
+1

LOL ... Evet, bu iş ... benim yapmaya çalıştığım şekilde çok daha kolay. Teşekkürler. – SledgeHammer

+1

Üretim, test ve gerçek sonuçlarla ilgili takip bölümlerini gerçekten takdir ediyorum, şerefe –