persona - fusionando dos objetos en C#
new objeto c# (5)
Tengo un modelo de objeto MyObject con varias propiedades. En un momento dado, tengo dos instancias de estos MyObject: instancia A y instancia B. Me gustaría copiar y reemplazar las propiedades en la instancia A con las de la instancia B si la instancia B no tiene valores nulos.
Si solo tuviera 1 clase con 3 propiedades, no hay problema, podría codificarla fácilmente (que es lo que empecé a hacer). Pero en realidad tengo 12 modelos de objetos diferentes con aproximadamente 10 propiedades cada uno.
¿Qué es una buena manera de hacer esto?
Esto es lo mismo que @Bas Answer pero para Fusionar 2 listas de objetos
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);
}
}
}
He escrito mi propia clase para este propósito: ObjectMerger .
Básicamente usa reflexiones (y puede ser lento debido a eso). También contiene más características, por ejemplo, el análisis de objetos para referencias cíclicas y la combinación también. Mi ObjectMerger también contiene un mecanismo para manejar clases más complejas como Delegate
o MemberInfo
. Esos serán copiados completamente, otros objetos en la clase se fusionan recursivamente.
La sintaxis es como:
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"
Lamento decir que NO ESTÁ PARA SU USO TAL CUAL, ya que faltan algunas bibliotecas externas en el repositorio en este momento debido a las limitaciones de mi empresa, pero se pueden reescribir fácilmente. Espero poder agregarlos en el futuro.
He intentado fusionar dos objetos en un tipo anónimo por Kyle Finley y funciona perfectamente.
Con el TypeMerger
la fusión es tan simple como
var obj1 = new {foo = "foo"};
var obj2 = new {bar = "bar"};
var mergedObject = TypeMerger.MergeTypes(obj1 , obj2 );
Eso es lo que tiene el objeto fusionado, aparte de eso, hay una disposición para ignorar propiedades específicas también. Puedes usar lo mismo para MVC3 también.
Puedes hacerlo utilizando la reflexión, pero como alguien dijo, tendrá una penalización de rendimiento.
Ya que está trabajando con un diseño de clase esperado, puede lograr el mismo objetivo utilizando un método de extensión como el siguiente:
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;
}
}
}
Y luego, en algún lugar de tu código:
someInstanceOfMyClass.Merge(someOtherInstanceOfMyClass);
Al final del día, ha centralizado esta operación en un método de extensión y si agrega o elimina una propiedad de su clase, solo necesita modificar la implementación del método de extensión y obtendrá todo listo.
Actualice Use AutoMapper en su lugar si necesita invocar mucho este método. Automapper construye métodos dinámicos utilizando Reflection.Emit
y será mucho más rápido que la reflexión ''.
Podrías copiar los valores de las propiedades utilizando la reflexión:
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);
}
}
Lo he hecho genérico para garantizar la seguridad del tipo. Si desea incluir propiedades privadas, debe usar una anulación de Type.GetProperties() , especificando banderas de enlace.