2012-11-03 16 views
5

Ho due istanze degli stessi oggetti, o1 e o2. Se sto facendo cose comeattraversa un oggetto e trova le proprietà non nulle

if (o1.property1 != null) o1.property1 = o2.property1 

per tutte le proprietà nell'oggetto. Quale sarebbe il modo più efficiente per scorrere tutte le proprietà in un oggetto e farlo? Ho visto persone che usano PropertyInfo per controllare nulll delle proprietà, ma sembra che possano passare attraverso la collezione PropertyInfo ma non collegare l'operazione delle proprietà.

Grazie.

risposta

12

Si può fare questo con la riflessione:

public void CopyNonNullProperties(object source, object target) 
{ 
    // You could potentially relax this, e.g. making sure that the 
    // target was a subtype of the source. 
    if (source.GetType() != target.GetType()) 
    { 
     throw new ArgumentException("Objects must be of the same type"); 
    } 

    foreach (var prop in source.GetType() 
           .GetProperties(BindingFlags.Instance | 
               BindingFlags.Public) 
           .Where(p => !p.GetIndexParameters().Any()) 
           .Where(p => p.CanRead && p.CanWrite)) 
    { 
     var value = prop.GetValue(source, null); 
     if (value != null) 
     { 
      prop.SetValue(target, value, null); 
     } 
    } 
} 
+0

Grazie, Jon, funziona perfettamente! – NewDTinStackoverflow

2

A giudicare dal vostro esempio penso che la vostra ricerca di qualcosa di simile:

static void CopyTo<T>(T from, T to) 
{ 
    foreach (PropertyInfo property in typeof(T).GetProperties()) 
    { 
     if (!property.CanRead || !property.CanWrite || (property.GetIndexParameters().Length > 0)) 
      continue; 

     object value = property.GetValue(to, null); 
     if (value != null) 
      property.SetValue(to, property.GetValue(from, null), null); 
    } 
} 
+0

vorrei fare una versione generica di quella di garantire lo stesso tipo di entrambi gli oggetti :) – khellang

+0

@khellang grande idea :), ha cambiato il mio esempio –

+0

Great stuff! :) – khellang

2

Se avete intenzione di utilizzare questo molte volte, si potrebbe utilizzare un'espressione compilata per prestazioni migliori:

public static class Mapper<T> 
{ 
    static Mapper() 
    { 
     var from = Expression.Parameter(typeof(T), "from"); 
     var to = Expression.Parameter(typeof(T), "to"); 

     var setExpressions = typeof(T) 
      .GetProperties() 
      .Where(property => property.CanRead && property.CanWrite && !property.GetIndexParameters().Any()) 
      .Select(property => 
      { 
       var getExpression = Expression.Call(from, property.GetGetMethod()); 
       var setExpression = Expression.Call(to, property.GetSetMethod(), getExpression); 
       var equalExpression = Expression.Equal(Expression.Convert(getExpression, typeof(object)), Expression.Constant(null)); 

       return Expression.IfThen(Expression.Not(equalExpression), setExpression); 
      }); 

     Map = Expression.Lambda<Action<T, T>>(Expression.Block(setExpressions), from, to).Compile(); 
    } 

    public static Action<T, T> Map { get; private set; } 
} 

E utilizzare in questo modo:

Mapper<Entity>.Map(e1, e2); 
Problemi correlati