2013-08-07 52 views
0

我已經做了基本的東西,但我堅持創造實際LambaExpresion:如何創建一個LambdaExpression,所有副本匹配性能

任何人有我想要與寫些指點? var COPYEXPRESSION = ...

public Expression<Func<TSource, TDestination>> GetOrCreateMapExpression<TSource, TDestination>() 
{ 
    return (Expression<Func<TSource, TDestination>>) 
     _expressionCache.GetOrAdd(new TypePair(typeof(TSource), typeof(TDestination)), tp => 
     { 
      return CreateMapExpression(tp.SourceType, tp.DestinationType); 
     }); 
} 

private LambdaExpression CreateMapExpression(Type source, Type destination) 
{ 
    ParameterExpression instanceParameter = Expression.Parameter(source); 


    var sourceMembers = source.GetProperties(); 
    var destMembers = destination.GetProperties(); 
    var matchingMembers = sourceMembers.Select(s => 
     new 
     { 
      Source = s, 
      Dest = destMembers.FirstOrDefault(d => 
       d.Name.Equals(s.Name) && d.PropertyType == s.PropertyType) 
     }).Where(map => map.Dest != null).ToArray(); 


    var COPYEXPRESSION = ... 

    return Expression.Lambda(COPYEXPRESSION , instanceParameter); 
} 

更新

我得到的返回類型是正確的,但是當單元測試這一點,映射類正在對屬性空。

private LambdaExpression CreateMapExpression(Type source, Type destination) 
{ 
    ParameterExpression instanceParameter = Expression.Parameter(source); 
    var instance2Parameter = Expression.New(destination); 
    LabelTarget returnTarget = Expression.Label(destination); 

    var sourceMembers = source.GetProperties().Where(p => p.GetMethod.IsPublic); 
    var destMembers = destination.GetProperties().Where(p => p.SetMethod.IsPublic); 
    var matchingMembers = sourceMembers.Select(s => 
     new 
     { 
      Source = s, 
      Dest = destMembers.FirstOrDefault(d => 
       d.Name.Equals(s.Name) && d.PropertyType == s.PropertyType) 
     }).Where(map => map.Dest != null).ToArray(); 

    var block = Expression.Block(Expression.Block(
     matchingMembers.Select(p => 
      Expression.Assign(
       Expression.Property(instance2Parameter, p.Dest), 
       Expression.Property(instanceParameter, p.Source)))), 
       Expression.Label(returnTarget, instance2Parameter)); 


    return Expression.Lambda(block, instanceParameter); 
} 

解決方案

這爲我工作:

return Expression.Lambda(Expression.MemberInit(Expression.New(destination), 
     matchingMembers.Select(p => 
      Expression.Bind(p.Dest, Expression.Property(instanceParameter, p.Source)))), 
      instanceParameter); 
+0

您不需要'd.Name.Equals(s.Name)'來比較兩個字符串.. 'd.Name == s.Name'就足夠了(而且它更具可讀性)。 – xanatos

回答

1

鑑於

ParameterExpression instanceParameter = Expression.Parameter(source); 
ParameterExpression instance2Parameter = Expression.Parameter(destination); 

你需要兩個參數,一個用於來源,一個用於目標...

,除非你正在建設一個新的目標,那麼你就需要一個Expression.Variableinstance2Parameter在這裏您可以把Expression.New

var block = Expression.Block(
       matchingMembers.Select(p =>  
        Expression.Assign(
         Expression.Property(instance2Parameter, p.Dest), 
         Expression.Property(instanceParameter, p.Source))) 

這是一個包含所有Expression.Assign

注意一個塊,你應該檢查存在DestSource中的吸氣劑(但它可能更好地在sourceMembers.Select中執行)。

+0

謝謝,當我不在時鐘時試試這個:) –

+0

我錯過了我認爲的回報部分。它應該是一個Func ,所以讓instance2Paramter是一個Expression.New innstead讓我創建對象,但我需要在方法被複制後返回。 –

相關問題