If I have a C# class
public class Foo
{
public int? a { get; set; }
public int? b { get; set; }
}
And two instances of that class
var foo1 = new Foo() { a = 1 };
var foo2 = new Foo() { b = 1 };
How could I copy the values from both objects to create a new instance of Foo
that contained the values from both foo1
and foo2
?
In Javascript this would be as simple as
var foo3 = Object.assign({}, foo1, foo2);
If I have a C# class
public class Foo
{
public int? a { get; set; }
public int? b { get; set; }
}
And two instances of that class
var foo1 = new Foo() { a = 1 };
var foo2 = new Foo() { b = 1 };
How could I copy the values from both objects to create a new instance of Foo
that contained the values from both foo1
and foo2
?
In Javascript this would be as simple as
var foo3 = Object.assign({}, foo1, foo2);
Share
Improve this question
edited Jan 10, 2023 at 8:30
Vivek Nuna
1
asked Nov 3, 2016 at 13:38
kavunkavun
3,3814 gold badges26 silver badges45 bronze badges
4
|
4 Answers
Reset to default 9you could create a method which merges objects via reflection. But beware, this is slow an can generally not used in C#.
Care must be taken to skip "empty" properties. In your case these are value types. In my example implementation, every property is skipped, if its the default value of that type (for int this is 0):
public T CreateFromObjects<T>(params T[] sources)
where T : new()
{
var ret = new T();
MergeObjects(ret, sources);
return ret;
}
public void MergeObjects<T>(T target, params T[] sources)
{
Func<PropertyInfo, T, bool> predicate = (p, s) =>
{
if (p.GetValue(s).Equals(GetDefault(p.PropertyType)))
{
return false;
}
return true;
};
MergeObjects(target, predicate, sources);
}
public void MergeObjects<T>(T target, Func<PropertyInfo, T, bool> predicate, params T[] sources)
{
foreach (var propertyInfo in typeof(T).GetProperties().Where(prop => prop.CanRead && prop.CanWrite))
{
foreach (var source in sources)
{
if (predicate(propertyInfo, source))
{
propertyInfo.SetValue(target, propertyInfo.GetValue(source));
}
}
}
}
private static object GetDefault(Type type)
{
if (type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
usage:
var foo3 = CreateFromObjects(foo1, foo2);
There is no direct method for this, But you can fulfil your requirement this way.
var foo3 = new Foo() {a = foo1.a, b = foo2.b };
Vivek's answer is the correct one. Because Object.Assign is part of the larger Inheritance vs Composition discussion. This is not so simple in javascript, where you need Object.Assign, but in C# you can compose a class in your own class by just instantiating it and making it a property. You really do it all the time.
Javascript with it's prototypal inheritance, you're really just linking objects. So inheritance (classical) does not exists there.
Check this video, it's very enlightening: Inheritance vs Composition
using Newtonsoft.Json;
.
.
.
var newFoo = JsonConvert.DeserializeObject<Foo>(JsonConvert.SerializeObject(oldFoo));
regards, Oli
foo1
andfoo2
will both always have values fora
andb
. So you would just be copying the values offoo2
into the target. You could makea
andb
nullable and write a version which only sets non-null values. – Lee Commented Nov 3, 2016 at 13:42var foo3 = new Foo() {a = foo1.a ?? foo2.a, b = foo1.b ?? foo2.b };
– Theo Commented Nov 3, 2016 at 13:49