fusion de deux objets en C#
j'ai un modèle D'objet MyObject avec diverses propriétés. A un moment, j'ai deux instances de ces Myobjects: instance A et instance B. j'aimerais copier et remplacer les propriétés de l'instance a par celles de l'instance B si l'instance B a des valeurs non nulles.
si j'avais seulement 1 classe avec 3 Propriétés, pas de problème, je pourrais facilement la coder (c'est ce que j'ai commencé à faire). Mais j'ai en fait 12 modèles d'objets différents avec environ 10 propriétés chacun.
Qu'est-ce que une bonne façon de le faire?
5 réponses
mise à Jour
Utilisez AutoMapper à la place, si vous devez beaucoup invoquer cette méthode. Automapper construit des méthodes dynamiques en utilisant Reflection.Emit
et sera beaucoup plus rapide que de réflexion.'
vous pouvez copier les valeurs des propriétés en utilisant reflection:
public void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
Je l'ai fait générique pour assurer la sécurité du type. Si vous souhaitez inclure les propriétés privées, vous devez utiliser un remplacement de Type.GetProperties (), spécifiant les drapeaux de liaison.
j'ai essayé fusionner deux objets dans un Type anonyme par Kyle Finley et c'est le travail parfait.
TypeMerger
la fusion est aussi simple que
var obj1 = new {foo = "foo"};
var obj2 = new {bar = "bar"};
var mergedObject = TypeMerger.MergeTypes(obj1 , obj2 );
c'est ça que vous avez obtenu l'objet fusionné, en dehors de cela, il y a une disposition à ignorer les propriétés spécifiques. Vous pouvez utiliser la même chose pour MVC3 aussi.
vous pouvez le faire en utilisant la réflexion, mais comme quelqu'un l'a dit, il aura une pénalité de performance.
puisque vous travaillez avec un design de classe attendu, vous pouvez atteindre le même objectif en utilisant une méthode d'extension comme so:
public static class MyClassExtensions
{
public static void Merge(this MyClass instanceA, MyClass instanceB)
{
if(instanceA != null && instanceB != null)
{
if(instanceB.Prop1 != null)
{
instanceA.Prop1 = instanceB.Prop1;
}
if(instanceB.PropN != null)
{
instanceA.PropN = instanceB.PropN;
}
}
}
someInstanceOfMyClass.Merge(someOtherInstanceOfMyClass);
à la fin de la journée vous avez centralisé cette opération dans une méthode d'extension et si vous ajoutez ou supprimez une propriété de votre classe, vous avez seulement besoin de modifier la méthode d'extension mise en œuvre et vous obtiendrez tout fait.
j'ai écrit ma propre classe dans ce but: ObjectMerger.
Fondamentalement, il utilise des réflexions (et peut être lent à cause de cela). Il contient également plus de fonctionnalités, par exemple parsing objets pour les références cycliques et les fusionner aussi. Mon ObjectMerger contient également un mécanisme pour gérer des classes plus complexes comme Delegate
ou MemberInfo
. Ceux-ci seront copiés complètement, les autres objets de la classe sont fusionnés récursivement.
la Syntaxe est La suivante comme:
var initialInstance = new MyObjectBase(); // Initialize first object
var properInstance = new MyObjectWithAlgorithms(); // Initialize second object
var result = ObjectMerger.MergeObjects(properInstance, initialInstance); // Merge Objects into type of "properInstance"
je suis désolé de dire que ce n'est pas pour être utilisé tel quel, parce que certaines bibliothèques externes sont manquantes dans le dépôt en ce moment en raison de limitations dans mon entreprise, mais elles peuvent facilement être réécrites. J'espère pouvoir les ajouter à l'avenir.
c'est la même réponse que @Bas mais pour la fusion de 2 objets listes
public class Copycontents
{
public static void Work<T>(IList<T> targetList, IList<T> sourceList, Func<T, int> selector)
{
var matchingPrimaryKey = targetList.Select(x => selector(x)).ToList();
foreach (var thismatchingPrimaryKey in matchingPrimaryKey)
{
CopyValues<T>(targetList.Single(x => selector(x) == thismatchingPrimaryKey),
sourceList.Single(x => selector(x) == thismatchingPrimaryKey));
}
}
private static void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
}