2016-06-15 2 views
0

J'attache de construire un arbre d'expression qui représenterait cette lambda:C# Construction d'une Expression d'action avec un bloc de code

Action<TFrom, TTo> map = 
    (from, to) => 
    { 
     to.Property1 = (Nullable<TTo>)from.Property1; 
     to.Property2 = (Nullable<TTo>)from.Property2; 
     // ...continued for all properties 
    }; 

Essentiellement, je suis en train de cartographier les propriétés non-nullables d'une classe à la Nullable<T> propriétés d'une autre classe qui partagent le même nom de propriété.

Je l'ai écrit (incorrect) arbre dans ma tentative de faire:

SomeObjWithOutNullable i = new SomeObjWithOutNullable(); // Not "object".. doh 
SomeObjWithNullable j = new SomeObjWithNullable(); 

ParameterExpression p1 = Expression.Parameter(typeof(SomeObjWithOutNullable), "from"); 
ParameterExpression p2 = Expression.Parameter(typeof(SomeObjWithNullable), "to"); 

MemberExpression m1 = Expression.PropertyOrField(p1, "Property1"); 
MemberExpression m2 = Expression.PropertyOrField(p2, "Property1"); 
BinaryExpression body = Expression.Assign(m1, m2); 
LambdaExpression lambda = Expression.Lambda<Action<SomeObjWithOutNullable,SomeObjWithNullable>>(body, new[] { p1,p2 }); 

var action = lambda.Compile(); 
action(i,j); 

Cela ne compile pas. Je reçois cette exception lorsque je tente de:

Delegate 'System.Action<SomeObjWithOutNullable,SomeObjWithNullable>' has some invalid arguments 
Argument 1: cannot convert from 'object' to 'SomeObjWithNullable' 
Argument 2: cannot convert from 'object' to 'SomeObjWithNullable' 

Je sais que je dois encore ajouter dans la conversion de type, mais je ne peux pas sembler comprendre comment faire même l'affectation correctement.

+0

Actuellement, les expressions que vous avez écrit à générer: '(de, à) = > new SomeObjWithOutNullable(). Property1 = new SomeObjWithNullable(). Property2; 'C'est assez loin du code que vous croyez écrire ... – Servy

+0

Oui, j'ai corrigé cette faute de frappe. Je suppose que la question se rapporte plus à la cession elle-même. Une fois que je peux descendre cette partie, je peux travailler sur le reste. – Noahm888

+0

Vous n'avez pas édité la question du tout, donc apparemment vous n'avez * pas * résolu ce problème. – Servy

Répondre

0

Ok, j'ai trouvé la solution:

void NullPropertyConvertionAction<TSource, TTarget>(TSource source, TTarget target) 
{ 
    var sourceDictionary = typeof(TSource).GetProperties() 
     .ToDictionary(s => 
      s.Name. 
      StringComparer.InvariantCultureIgnoreCase 
     ); 
    ParameterExpression p1 = Expression.Parameter(typeof(TSource), "from"); 
    ParameterExpression p2 = Expression.Parameter(typeof(TTarget), "to"); 
    var expressionBodies = new List<BinaryExpression>(); 
    foreach (var member in typeof(TTarget).GetProperties() 
     .Where(p=> p.PropertyType.IsGenericType 
     && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))) 
    { 
     if (sourceDictionary.ContainsKey(member.Name)) 
     { 
      MemberExpression m1 = Expression.PropertyOrField(p1, sourceDictionary[member.Name].Name); 
      MemberExpression m2 = Expression.PropertyOrField(p2, member.Name); 
      BinaryExpression body = Expression.Assign(m2, Expression.Convert(m1, member.PropertyType)); 
      expressionBodies.Add(body); 
     } 
    } 
    BlockExpression block = Expression.Block(expressionBodies.ToArray()); 
    LambdaExpression lambda = Expression.Lambda<Action<TSource,TTarget (block, new[] { p1,p2 }); 
    Action<TSource,TTarget> action = (Action<TSource,TTarget>)lambda.Compile(); 
    action(source,target); 
} 
0

Vous avez jeté les informations de type lorsque vous downCast votre lambda à LambdaExpression. La meilleure façon de résoudre ce serait d'utiliser var:

var lambda = Expression.Lambda ... 

Vous pouvez également utiliser le bon type complet:

Expression<Action<TSource, TTarget>> lambda = Expression.Lambda ... 
+0

Merci pour le conseil. Je le ferai – Noahm888