Merging Two Objects in C#

Merging two objects in C#

Update
Use AutoMapper instead if you need to invoke this method a lot. Automapper builds dynamic methods using Reflection.Emit and will be much faster than reflection.'

You could copy the values of the properties using 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);
}
}

I've made it generic to ensure type safety. If you want to include private properties you should use an override of Type.GetProperties(), specifying binding flags.

Merge multiple C# object

Based on this answer: https://stackoverflow.com/a/3862241/9748260

I modified the provided type builder a little to look like this:

public static class MyTypeBuilder
{
public static Type CompileResultType(List<PropertyInfo> yourListOfFields, string typeName)
{
TypeBuilder tb = GetTypeBuilder(typeName);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

// NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
foreach (var field in yourListOfFields)
CreateProperty(tb, field.Name, field.PropertyType);

Type objectType = tb.CreateType();
return objectType;
}

private static TypeBuilder GetTypeBuilder(string typeSignature)
{
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
return tb;
}

private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();

getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);

MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });

ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();

setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);

setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);

propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}

Then I created a method to merge the objects:

public static object Merge(object obj1, object obj2, string newTypeName)
{
var obj1Properties = obj1.GetType().GetProperties();
var obj2Properties = obj2.GetType().GetProperties();
var properties = obj1Properties.Concat(obj2Properties).ToList();
Type mergedType = MyTypeBuilder.CompileResultType(properties, newTypeName);
object mergedObject = Activator.CreateInstance(mergedType);
var mergedObjectProperties = obj2.GetType().GetProperties();

foreach(var property in obj1Properties)
{
mergedObject.GetType().GetProperty(property.Name).SetValue(mergedObject, obj1.GetType().GetProperty(property.Name).GetValue(obj1, null) , null);
}

foreach(var property in obj2Properties)
{
mergedObject.GetType().GetProperty(property.Name).SetValue(mergedObject, obj2.GetType().GetProperty(property.Name).GetValue(obj2, null) , null);
}

return mergedObject;
}

To test the result:

object obj1 = new
{
ID = 1,
Title = "text",
Test = new
{
Number = 20,
IsSomething = false
}
};

object obj2 = new
{
Age = 22
};
object merged = Merge(obj1, obj2, "merged");

foreach(var x in merged.GetType().GetProperties())
{
Console.WriteLine($"{x.Name} = {x.GetValue(merged, null)}");
}

Console.ReadLine();

The output is:

ID = 1
Title = text
Test = { Number = 20, IsSomething = False }
Age = 22

To explain this briefly, the idea is to create a new object which have the properties of both objects and copy their values.

How to merge two objects, overriding null values

The best way is to simply write manual mappers. But if you want something that will perform this for you in every simple POCO case where no constructors are involved, the following will use reflection to:

  • create a new output object
  • map the override prop if the value is not null
  • map the base prop if the override prop value is null
  • and return the cloned object
public static class Merger
{
public static T CloneAndMerge<T>(T baseObject, T overrideObject) where T : new()
{
var t = typeof(T);
var publicProperties = t.GetProperties();

var output = new T();

foreach (var propInfo in publicProperties)
{
var overrideValue = propInfo.GetValue(overrideObject);
var defaultValue = !propInfo.PropertyType.IsValueType
? null
: Activator.CreateInstance(propInfo.PropertyType);
if (overrideValue == defaultValue)
{
propInfo.SetValue(output, propInfo.GetValue(baseObject));
}
else
{
propInfo.SetValue(output, overrideValue);
}
}

return output;
}
}

Please note, there is no optimization or caching here. I wouldn't recommend it for production code, but it is a simple way to accomplish what you are looking for.

C#: Merge two objects based on common identifier?

You can use Linq, like the following code :

1 - get the distinct servers, by id and name :

List<Server> distinctServers = company.Servers
.GroupBy(s => new { s.ServerId, s.ServerName })
.Select(s => new Server
{
ServerId = s.Key.ServerId,
ServerName = s.Key.ServerName,
Users = s.SelectMany(x => x.Users).ToList()
}).ToList();

2 - construct a new company or use the old:

Company result = new Company
{
CompanyName = company.CompanyName,
Servers = distinctServers
};
// or
company.Servers = distinctServers;

If you have list of companies, you can use the same code inside select function:

List<Company> companies = new List<Company> { company };
List<Company> companiesWithDistinctServers = companies
.Select(c => new Company
{
CompanyName = c.CompanyName,
Servers = c.Servers.GroupBy(s => new { s.ServerId, s.ServerName })
.Select(s => new Server
{
ServerId = s.Key.ServerId,
ServerName = s.Key.ServerName,
Users = s.SelectMany(x => x.Users).ToList()
}).ToList()
}).ToList();

i hope this help

Merge Two Object Data

This will work, but it doesn't cover all cases (only public properties get copied, no indexed properties):

    class MyClass
{
public string Text1 { get; set; }
public string Text2 { get; set; }
public string Text3 { get; set; }
public int Int1 { get; set; }
}

public static void Test()
{
var obj1 = new MyClass {Text1 = "Test1", Text2 = "Test2", Text3 = "Test3", Int1 = 0};
var obj2 = new MyClass {Text3 = "Another Test", Int1 = 1};

var obj3 = MergeObjects(obj1, obj2);
}

public static T MergeObjects<T>(T obj1, T obj2)
{
var objResult = Activator.CreateInstance(typeof(T));

var allProperties = typeof(T).GetProperties().Where(x => x.CanRead && x.CanWrite);
foreach (var pi in allProperties)
{
object defaultValue;
if (pi.PropertyType.IsValueType)
{
defaultValue = Activator.CreateInstance(pi.PropertyType);
}
else
{
defaultValue = null;
}

var value = pi.GetValue(obj2, null);

if (value != defaultValue)
{
pi.SetValue(objResult, value, null);
}
else
{
value = pi.GetValue(obj1, null);

if (value != defaultValue)
{
pi.SetValue(objResult, value, null);
}
}
}

return (T)objResult;
}

C# Merge 2 objects of the same with linq 2 object

Here's a way to accomplish this using reflection:

public class SomePropertyClass
{
public string VarA { get; set; }
public string VarB { get; set; }
}

static class Program
{
static void Main(string[] args)
{
SomePropertyClass v1 = new SomePropertyClass() { VarA = "item 1" };
SomePropertyClass v2 = new SomePropertyClass() { VarB = "item 2" };

var yo = v1.Combine(v2);
}

static public IEnumerable<object> Combine<T, U>(this T one, U two)
{
var properties1 = one.GetType().GetProperties().Where(p => p.CanRead && p.GetValue(one, null) != null).Select(p => p.GetValue(one, null));
var properties2 = two.GetType().GetProperties().Where(p => p.CanRead && p.GetValue(two, null) != null).Select(p => p.GetValue(two, null));

return new List<object>(properties1.Concat(properties2));
}
}

C# merge two objects together at runtime

Reflection would work. Something like:

public static void MergeWith<T>(this T primary, T secondary) {
foreach (var pi in typeof(T).GetProperties()) {
var priValue = pi.GetGetMethod().Invoke(primary, null);
var secValue = pi.GetGetMethod().Invoke(secondary, null);
if (priValue == null || (pi.PropertyType.IsValueType && priValue.Equals(Activator.CreateInstance(pi.PropertyType)))) {
pi.GetSetMethod().Invoke(primary, new object[]{secValue});
}
}
}

How to easily merge two anonymous objects with different data structure?

There's nothing built-in in the C# language to support your use case. Thus, the question in your title needs to be answered with "Sorry, there is no easy way".

I can offer the following alternatives:

  1. Do it manually:

    var man = new {
    name = new {
    first = man1.name.first,
    last = man2.name.first
    },
    age = man1.age,
    address = man2.address
    };
  2. Use a class instead of an anonymous type for the resulting type (let's call it CompleteMan). Then, you can

    • create a new instance var man = new CompleteMan(); ,
    • use reflection to collect the properties and values from your "partial men" (man1 and man2),
    • assign those values to the properties of your man.

    It's "easy" in the sense that the implementation will be fairly straight-forward, but it will still be a lot of code, and you need to take your nested types (name) into account.

    If you desperately want to avoid non-anonymous types, you could probably use an empty anonymous target object, but creating this object (var man = new { name = new { first = (string)null, last = (string)null, ...) is not really less work than creating a class in the first place.

  3. Use a dedicated dynamic data structure instead of anonymous C# classes:

    • The Newtonsoft JSON library supports merging of JSON objects.
    • Dictionaries can also be merged easily.
    • ExpandoObjects can be merged easily as well.


Related Topics



Leave a reply



Submit