2010-11-10 17 views
1

Nous avons deux classes qui ont exactement les mêmes accesseurs publics (et beaucoup d'entre eux), mais proviennent de différentes zones de la hiérarchie des objets; nous avons besoin de copier et comparer entre ces deux objets. Nous pourrions écrire manuellement un constructeur de copie et un opérateur de comparaison qui compare les valeurs des accesseurs du même nom, mais il semble qu'il y ait une meilleure façon de le faire en utilisant la réflexion et LINQ.Propre façon de comparer/copier entre des classes similaires

Exemple: nous avons la classe ClassA qui a 70 accesseurs; nous avons aussi la classe ClassB qui a 70 accesseurs, qui sont définis comme étant le même nom et le même type que les accesseurs de ClassA.

public class ClassA 
{ 
int OneInt {get; set;} 
int TwoInt {get; set;} 
... 
string OneString {get; set;} 
string AnotherString {get; set;} 
} 

public class ClassB 
{ 
int OneInt {get; set;} 
int TwoInt {get; set;} 
... 
string OneString {get; set} 
string AnotherString {get; set;} 
} 

Ce que je voudrais est un moyen simple d'utiliser la réflexion pour découvrir tous les accesseurs publics de ClassA, et utiliser ces noms pour définir les valeurs de l'accesseur respective sur ClassB à la valeur de l'accesseur sur Classe A. En gros, dans psuedocode:

foreach (string accName in ClassA.Accessors[]) 
    BInstance.Accessors[accName].Value = AInstance.Accessors[accName].Value; 

Et, bien sûr, la même chose pourrait être utilisé pour l'égalité des tests entre les deux classes. Ma connaissance de la réflexion C# et de LINQ n'est pas assez bonne pour savoir comment faire cela, mais je jurerais que c'est quelque chose de relativement simple.

Répondre

2

votre pseudocode rugueux est quelque peu précis. Permettez-moi de le nettoyer un peu:

foreach (var propertyA in typeof(ClassA).GetProperties()) 
{ 
    var propertyB = typeof(ClassB).GetProperty(propertyA.Name); 
    var valueA = propertyA.GetValue(objectA, null); 
    propertyB.SetValue(objectB, valueA, null); 
} 

De toute évidence, cela ne fait pas la vérification des erreurs et des trucs comme ça, mais il devrait faire le travail.

Vous pourriez le faire dans Linq, mais je ne pense pas que ce serait plus propre.

+0

J'aime celui-là; c'est très clair. Je savais que j'étais dans le bon niveau avec le code! :) –

+0

Utilisé avec des modifications mineures; fonctionne bien! –

5

Comment l'utilisation AutoMapper:

Mapper.CreateMap<ClassA, ClassB>(); 

puis:

ClassA classA = ... 
ClassB classB = Mapper.Map<ClassA, ClassB>(classA); 

Il est essentiellement une implémentation de votre pseudo-code.

+0

Nice; C'est définitivement une option, bien que je soupçonne toujours qu'il y a une façon "intelligente" de faire cela en C# à la vanille. –

+0

Oui bien sûr, ce serait d'utiliser la réflexion. Mais si vous voulez qu'il soit vraiment intelligent (gérer des cas de null par exemple, des types incompatibles, ...) vous aurez besoin d'écrire beaucoup de code C# vanille. Alors pourquoi l'écrire quand quelqu'un l'a déjà fait, l'a testé, documenté, emballé dans un assemblage réutilisable, mesuré ses performances, ... pour que vous puissiez maintenant vous concentrer sur le vrai métier de votre application au lieu de faire de la plomberie? –

+0

Votre point est bien pris, mais je pense qu'il y a de la valeur dans les techniques d'apprentissage, même lorsqu'elles sont déjà implémentées dans des bibliothèques externes; il s'agit de gagner en profondeur avec la langue de manière pratique. –