2010-10-28 11 views
5

Ho una nota classe di clienti POCO per tornare dal mio metodo. Tuttavia, popolo solo le proprietà specificate da un'espressione sempre diversa p => new {p.id, p.name} ad esempio come parametro del metodo.Quale codice C#/Linq copia tutti i valori dei nomi delle proprietà corrispondenti tra due oggetti senza conoscerne il tipo?

In qualche modo ho bisogno di copiare tutti i campi corrispondenti tra questi due oggetti.

var returnObject = IList<Customer>(); 
var partialFieldObject = DC.Customers.Select(expParameter); // wont know the fields 

foreach(var partialRecord in partialFieldObject) 
{ foreach (var property in partialRecord // Pseudo code) 
    { 
     returnObject[property] = property.value; // More Pseudo code 
    } 
} 
End result is a strongly typed Customer POCO returned that only has the selected fields populated with values. 
+0

Per "corrispondenza" intendo copiare i valori di tutte le proprietà con lo stesso nome. –

risposta

16

Alcuni semplice riflessione fa il trucco, assumendo le proprietà sulla partialFieldObject line up esattamente (case-sensitive), con immobili in Customer .. .

void SetProperties(object source, object target) 
{ 
    var customerType = target.GetType(); 
    foreach (var prop in source.GetType().GetProperties()) 
    { 
     var propGetter = prop.GetGetMethod(); 
     var propSetter = customerType.GetProperty(prop.Name).GetSetMethod(); 
     var valueToSet = propGetter.Invoke(source, null); 
     propSetter.Invoke(target, new[] { valueToSet }); 
    } 
} 
+0

Delicious Reflection bontà! O qualcosa di simile! –

+1

Fantastico! Ho dovuto aggiungere alcuni assegni di valore nullo, ma in seguito ha funzionato come un incantesimo. Molte grazie! –

+0

questa riflessione funziona ha perdita di prestazioni. è meglio usare le assegnazioni di espressioni Linq e compilarlo per l'intera applicazione. – Amir

6

Si può usare AutoMapper - è costruito per fare queste cose penso

+0

Il problema è che AutoMapper non esegue il mapping quando non è in grado di determinare il tipo. Vede "oggetto" che non ha proprietà. –

+2

@ Dr.Zim Guardando all'API, è possibile utilizzare un modulo generico della funzione CreateMap o il parametro basato, che consente di passare i tipi. Quindi puoi fare 'AutoMapper.Mapper.CreateMap (source.GetType(), destination.GetType())' – AaronLS

2

Adattamento dahlbyk 's accettate answer, ho finito per usare il seguente in un costruttore che ha accettato una base di tipo e aveva bisogno di rispecchiare il contenuto:

var thisType = this.GetType(); 
foreach (var prop in baseObj.GetType().GetProperties() 
    .Where(p => thisType.GetProperty(p.Name) != null)) 
{ 
    var propGetter = prop.GetGetMethod(); 
    var propSetter = thisType.GetProperty(prop.Name).GetSetMethod(); 
    if (propSetter != null) 
     propSetter.Invoke(this, new[] { propGetter.Invoke(baseObj, null) }); 
} 

Fondamentalmente, passo attraverso ogni proprietà nel tipo baseObj dove this tipo ha una proprietà con un nome corrispondente, e individuare il metodo get del tipo baseObj nonché il metodo set per l'denominato corrispondente struttura su this digitare e se è disponibile un metodo set su this, richiamarlo utilizzando il metodo restituito dall'invocazione del metodo get sul tipo baseObj.

Funziona bene per il pubblico & proprietà private di qualsiasi tipo (corrispondente) su entrambi i tipi.

Nota: Avrete bisogno di un riferimento alla System.Linq per la .Where() func nel ciclo

0
public static void CopyPropertiesTo<T, TU>(this T source, TU dest) 
    { 

     var sourceProps = typeof (T).GetProperties().Where(x => x.CanRead).ToList(); 
     var destProps = typeof(TU).GetProperties() 
       .Where(x => x.CanWrite) 
       .ToList(); 

     foreach (var sourceProp in sourceProps) 
     { 
      if (destProps.Any(x => x.Name == sourceProp.Name)) 
      { 
       var p = destProps.First(x => x.Name == sourceProp.Name); 
       p.SetValue(dest, sourceProp.GetValue(source, null), null); 
      } 

     } 

    } 
1

Non che diverso, proprio la forma più compatta e più pulito che ho trovato:

void CopyProperties(object src, object dest) { 
    foreach (var source in src.GetType().GetProperties().Where(p => p.CanRead)) { 
    var prop = dest.GetType().GetProperty(source.Name); 
    if (prop?.CanWrite == true) 
     prop.SetValue(dest, source.GetValue(src, null), null); 
    } 
} 
+0

In caso di lettura effettiva di questa riga: prop.SetValue (dest, source.GetValue (src, null), null); –

+1

Grazie, è stato copiato da un codice funzionante in questo modo, probabilmente ... –

0
void Copy(object copyToObject, object copyFromObject) 
{ 
    BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; 

    FieldInfo[] fields = copyFromObject.GetType().GetFields(flags); 
    for (int i = 0; i < fields.Length; ++i) 
    { 
     FieldInfo fromField = copyFromObject.GetType().GetField(fields[i].Name, flags); 
     FieldInfo toField = copyToObject.GetType().GetField(fields[i].Name, flags); 
     if(fromField != null) 
     { 
      toField.SetValue(copyToObject, fromField.GetValue(copyFromObject)); 
     } 
    } 
} 
+0

Puoi approfondire la tua risposta? Pubblicare solo il codice spesso non è molto utile. –

Problemi correlati