Copying All Class Fields and Properties To Another Class - c#

I have a class which normally contains Fields, Properties. What i want to achieve is instead of this:
class Example
{
public string Field = "EN";
public string Name { get; set; }
public int? Age { get; set; }
public List<string> A_State_of_String { get; set; }
}
public static void Test()
{
var c1 = new Example
{
Name = "Philip",
Age = null,
A_State_of_String = new List<string>
{
"Some Strings"
}
};
var c2 = new Example();
//Instead of doing that
c2.Name = string.IsNullOrEmpty(c1.Name) ? "" : c1.Name;
c2.Age = c1.Age ?? 0;
c2.A_State_of_String = c1.A_State_of_String ?? new List<string>();
//Just do that
c1.CopyEmAll(c2);
}
What i came up with but doesn't work as expected.
public static void CopyEmAll(this object src, object dest)
{
if (src == null) {
throw new ArgumentNullException("src");
}
foreach (PropertyDescriptor item in TypeDescriptor.GetProperties(src)) {
var val = item.GetValue(src);
if (val == null) {
continue;
}
item.SetValue(dest, val);
}
}
Problems:
Although i checked for null, it seems to bypass it.
Doesn't seem to copy Fields.
Notes:
I don't want to use AutoMapper for some technical issues.
I want the method to copy values and not creating new object. [just mimic the behavior i stated in the example]
I want the function to be recursive [if the class contains another classes it copies its values too going to the most inner one]
Don't want to copy null or empty values unless i allow it to.
Copies all Fields, Properties, or even Events.

Based on Leo's answer, but using Generics and copying also the fields:
public void CopyAll<T>(T source, T target)
{
var type = typeof(T);
foreach (var sourceProperty in type.GetProperties())
{
var targetProperty = type.GetProperty(sourceProperty.Name);
targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
}
foreach (var sourceField in type.GetFields())
{
var targetField = type.GetField(sourceField.Name);
targetField.SetValue(target, sourceField.GetValue(source));
}
}
And then just:
CopyAll(f1, f2);

You can use serialization to serialize object A and deserialize as object B - if they have very same structure, you can look here for object deep copy.
Deep cloning objects
I know you don't want to use Automapper, but if the types have only SIMILAR structure, you should maybe use Automapper which is based on reflection. You can download a nuget and find some information here:
https://www.nuget.org/packages/AutoMapper/
your code then will look like
public TOutput CopyAll<TInput, TOutput>(TInput input)
{
var config = new MapperConfiguration(cfg => cfg.CreateMap<TInput, TOutput>());
IMapper mapper = config.CreateMapper();
return mapper.Map<TOutput>(vstup);
}

Related

Dynamically copy certain properties between two class instances

I am attempting to write a piece of code that can take two instances of the same object, and copy some properties from the first one to the second one, dynamically. A little twist is that I only have access to the objects, through an interface they both inherit.
I have created a Copyable attribute that will be used to mark what properties can be copied.
I then managed to successfully do this using the PropertyInfo.GetMethod and PropertyInfo.SetMethod, however the resulting code is too slow. When comparing to statically assigning properties at compile time - this approach is ~20 times slower.
Here is my initial implementation using pure reflection.
using System;
using System.Linq;
namespace ConsoleApp58
{
interface IInterface
{
int Id { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
class CopyableAttribute : Attribute { }
class Child : IInterface
{
public int Id { get; set; }
[Copyable]
public int CopyableProp { get; set; }
}
class Program
{
static void Main(string[] args)
{
var source = new Child() {Id = 1, CopyableProp = 42};
var target = new Child() {Id = 2, CopyableProp = 0};
CopyProps(source, target);
}
static void CopyProps(IInterface source, IInterface target)
{
var props = target.GetType()
.GetProperties()
.Where(p => p.IsDefined(typeof(CopyableAttribute), false))
.ToArray();
foreach (var prop in props)
{
var value = prop.GetMethod.Invoke(source, new object[] { });
prop.SetMethod.Invoke(target, new [] {value});
}
}
}
}
This works, but its slow, so I decided to attempt and create an expression tree that will build a lambda that can call the getters and setters, however I can't seem to make it work.
I tried following this SO question, however, that implementation relies on the fact that I know what's the type of my object that I'm taking the properties from.
However, in my case the properties are defined as part of child classes, and I have no access to them in my IInterface.
Hence, I'm asking here. Is there a (fast) way for me to copy the value of specific properties, between instances of two objects, by referring to them only through their common interface.
You can generate Action<IInterface, IInterface> by Expression API. Try this code:
private static Expression<Action<IInterface, IInterface>> CreateCopyMethod(Type type)
{
var props = type
.GetProperties()
.Where(p => p.IsDefined(typeof(CopyableAttribute), false))
.ToArray();
var s = Expression.Parameter(typeof(IInterface), "s");
var t = Expression.Parameter(typeof(IInterface), "t");
var source = Expression.Variable(type, "source");
var castToSource = Expression.Assign(source, Expression.Convert(s, type));
var target = Expression.Variable(type, "target");
var castToTarget = Expression.Assign(target, Expression.Convert(t, type));
var instructions = new List<Expression>
{
castToSource, castToTarget
};
foreach (var property in props)
{
var left = Expression.Property(target, property);
var right = Expression.Property(source, property);
var assign = Expression.Assign(left, right);
instructions.Add(assign);
}
var lambda = Expression.Lambda<Action<IInterface, IInterface>>(
Expression.Block(
new[] {source, target}, instructions),
s, t);
return lambda;
}
Usage
IInterface src = new Child
{
CopyableProp = 42
};
IInterface dst = new Child();
var copy = CreateCopyMethod(src.GetType()).Compile();
copy(src, dst);
Console.WriteLine(((Child)dst).CopyableProp); // 42
To improve performance consider usage Dictionary<Type, Action<IInterface, IInterface>> to cache implementation of already generated methods

SetValue Method throw Exception when using reflection

I'm trying to set value to properties in many objects.
I've a function that receive 2 parameters MyStructuredObjects and MyObject
MyStructuredObjects has a list of MyObjects.
This Function is a re-factory to remove a lot of 'if's.
I'd like to use ever the same object because the function it is used in a loop.If it is possible.
I've getting ever the exception 'Object does not match target'.
Sorry posting this, but I don't found problems like this, using List inside a Object structure.
Take a look :
public class MyStructuredObjects
{
public List<MyObject1> Object1 { get; set; }
public List<MyObject2> Object2 { get; set; }
public List<MyObject3> Object3 { get; set; }
public List<MyObject4> Object4 { get; set; }
public List<MyObject5> Object5 { get; set; }
}
private void SetValuesToObjectsToIntegrate<T>(ref MyStructuredObjects returnedObject, T obj)
{
Type t = obj.GetType();
var propertyInfo = new ObjectsToIntegrate().GetType().GetProperties();
var instance = Activator.CreateInstance(t);
foreach (var item in returnedObject.GetType().GetProperties())
{
var itemType = item.PropertyType;
if (t == itemType) // PASSING BY HERE OK , it finds the same type :P
{
item.SetValue(t, Convert.ChangeType(obj, item.PropertyType), null);
}
}
}
Update: The code should be:
item.SetValue(instance, Convert.ChangeType(obj, item.PropertyType), null);
I think I understand what you're trying to do.
It appears that you're trying to set properties like this:
var o2 = new List<MyObject2>();
var mso = new MyStructuredObjects();
SetValuesToObjectsToIntegrate(ref mso, o2);
So that mso will have its property Object2 set because the type of o2 matches the property type.
If that's the case, then you only need this code:
private void SetValuesToObjectsToIntegrate<T>(MyStructuredObjects returnedObject, T obj)
{
foreach (var propertyInfo in typeof(MyStructuredObjects).GetProperties())
{
if (typeof(T) == propertyInfo.PropertyType)
{
propertyInfo.SetValue(returnedObject, obj, null);
}
}
}
There's no need to pass MyStructuredObjects returnedObject by ref as you're not changing the instance of returnedObject.
Use this to call this code:
var o2 = new List<MyObject2>();
var mso = new MyStructuredObjects();
SetValuesToObjectsToIntegrate(mso, o2);
After this call I now get:

Get class properties in C# (whitout instantiating it)

I've a class "TradingStrategy", with n subclasses ("Strategy1, Strategy2 etc...").
I've a simple UI from which i can choose a subclass (I've got all the subclasses of the "TradingStrategy" class pretty easily).
What i want now is to print (in a datagridview, listbox, combobox, doesn't matter) all the public parameters of the choosen subclass.
I would prefer not to instantiate the subclasses.
namespace BackTester
{
class TradingStrategy
{
public string Name;
}
class MA_Test : TradingStrategy
{
new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
public int len = 12;
public float lots = 0.1F;
public bool trendFollow = true;
public MA_Test()
{
}
}
class MA_Test2 : TradingStrategy
{
new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
public int len = 24;
public float lots = 0.1F;
public bool trendFollow = true;
public MA_Test2()
{
}
}
}
With this code i can insert into a combo box every subclass of "TradingStrategy"
var type = typeof(TradingStrategy);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var t in types){
if (t.Name == "TradingStrategy") continue;
boxStrategy.Items.Add(t.Name);
}
I wanna be able to, from the combobox.Text, get all the properties name and values of the corrisponding subclass.
I think I've read (and tried) every post here and in other forum. Many use reflections.
What is the simplest way to get those prop/values?
Thanks
Why not just create an interface ITradingStrategy:
public interface ITradingStrategy
{
string Name { get; }
int len { get; }
float lots { get; }
bool trendFollow { get; }
}
And have all classes inherit from the interface then pull values from interface.
As was mentioned in the comments, you have to instantiate an instance of the class in order to set some values on it.
To get the public fields/properties and their types without instantiating the objects, you can use reflection as follows:
private static Dictionary<string, Type> GetFields(Type t)
{
var fields = new Dictionary<string, Type>();
foreach (var memberInfo in t.GetMembers(BindingFlags.Instance | BindingFlags.Public))
{
var propertyInfo = memberInfo as PropertyInfo;
var fieldInfo = memberInfo as FieldInfo;
if (propertyInfo != null)
{
fields.Add(propertyInfo.Name, propertyInfo.PropertyType);
}
if (fieldInfo != null)
{
fields.Add(fieldInfo.Name, fieldInfo.FieldType);
}
}
return fields;
}
If you already have the object, you can get all the public fields/values with this method.
private static Dictionary<string, object> GetValues(FileInfo o)
{
var values = new Dictionary<string, object>();
foreach (var memberInfo in o.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public))
{
var propertyInfo = memberInfo as PropertyInfo;
var fieldInfo = memberInfo as FieldInfo;
if (propertyInfo != null)
{
values.Add(propertyInfo.Name, propertyInfo.GetValue(o, null));
}
if (fieldInfo != null)
{
values.Add(fieldInfo.Name, fieldInfo.GetValue(o));
}
}
return values;
}
The following code is a very slow way to get all the types which derive from a given type, due to the way that the CLR implements GetTypes() and the fact there could be thousands of unrelated types in your code which makes the haystack to search even bigger. The only time you should use this method is if you dynamically load assemblies at runtime containing object definitions that you need to load. Unfortunately there is no other way to get this information at runtime:
var type = typeof(TradingStrategy);
var subtypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => p != type && type.IsAssignableFrom(p));
I would recommend that you store this list of types somewhere in your code, e.g. in an array, and iterate over it when you need to know all of your strategies:
private static readonly Type[] TradingStrategies =
{
typeof(Strategy1),
typeof(Strategy2),
typeof(Strategy3),
};
After reading Erik's answer. If you will never instantiate these classes, you could store this data in a configuration file, and use something like JSON.net to read it, or if you don't want to use an external library, XmlSerializer would work as well. In this case you would store each MATest as a Dictionary (which lends itself nicely to JSON.net's JObject. Using JSON.net, you would have a configuration file that looks like:
[
{
"MA_Test": {
"len": 12,
"lots": 0.1,
"trendFollow": true
},
"MA_Test2": {
"len": 24,
"lots": 0.1,
"trendFollow": true
}
}
]
Then read it with code that looks like:
public JObject ReadConfig(string configPath)
{
using (var filestream = File.Open(configPath, FileMode.Open))
using (var streamReader = new StreamReader(filestream))
using (var jsonTextReader = new JsonTextReader(streamReader))
{
var jsonSerializer = new JsonSerializer();
return jsonSerializer.Deserialize<JObject>(jsonTextReader);
}
}
Thank you all for you answers.
The simplest way I found to get the properties from an indirected instantiated class is this:
var strategy = activator.CreateInstance(Type.GetType("BackTester."+boxStrategy.Text));
foreach (FieldInfo prop in strategy.GetType().GetFields(BindingFlags.Public
| BindingFlags.Instance))
{
listBox1.Items.Add(prop.ToString() + " " + prop.GetValue(strategy));
}
Based on the code you've provided, there is no reason for there to be separate classes for each MA_Test (X DO NOT use underscores, hyphens, or any other nonalphanumeric characters.). Instead these should be the same class with different properties (not fields).
class TradingStrategy
{
public string Name { get; set; }
}
class MATest : TradingStrategy
{
// this is not needed if it is inherited by TradingStragegy
// You should be getting a warning that you are hiding
// the field/property
// public string Name { get; set; }
// Should probably be more descriptive
// e.g. LengthInFeet...
public int Length { get; set; }
public float Lots { get; set; }
// I recommended boolean properties to be prefixed with
// Is, Can, Has, etc
public bool CanTrendFollow { get; set; }
}
// Somewhere Else...
var MATests = new List<MATest>()
{
new MATest()
{
Name = "MATest",
Length = 12,
Lots = 0.1F,
CanTrendFollow = true
},
new MATest()
{
Name = "MATest",
Length = 24,
Lots = 0.1F,
CanTrendFollow = true
},
}
Now instead of costly Reflection and Activator, just create the list classes once (manually, from config or even a database), and they can be used for whatever you need.

Copy the content of one collection to another using a generic function

Say I have two collections viz List<PersonOld> and List<PersonNew> as under.
private List<PersonOld> GetOldPersonRecord()
{
var sourceList = new List<PersonOld>();
for (int i = 1; i <= 10; i++)
sourceList.Add(new PersonOld { PersonId = i, PersonName = "Name" + i.ToString() });
return sourceList;
}
The need is to fill the List<PersonNew> with the value of List<PersonOld>.
And it needs to be generic ..means given any source collection and destination to the utility function, it needs to fill the destination collection from source.
I am trying
public List<T2> Fill<T1, T2>(List<T1> Source, List<T2> Destination)
{
Type type1 = typeof(T1);
var type1List = type1.GetProperties();
Type type2 = typeof(T2);
var type2List = type2.GetProperties();
//determine the underlying type the List<> contains
Type elementType = type1.GetGenericArguments()[0];
foreach (object record in Source)
{
int i = 0;
object[] fieldValues = new object[Destination.Count];
foreach (PropertyInfo prop in Destination)
{
MemberInfo mi = elementType.GetMember(prop.Name)[0];
if (mi.MemberType == MemberTypes.Property)
{
PropertyInfo pi = mi as PropertyInfo;
fieldValues[i] = pi.GetValue(record, null);
}
else if (mi.MemberType == MemberTypes.Field)
{
FieldInfo fi = mi as FieldInfo;
fieldValues[i] = fi.GetValue(record);
}
i++;
}
//Destination..Add(fieldValues);
}
}
and invocation
var source = GetOldPersonRecord();
var result = Utility.Fill(source, new List<PersonNew>());
But no luck..please help
The entities are as under
PersonNew
public class PersonNew
{
public int PersonId { get; set; }
public string PersonName { get; set; }
}
PersonOld
public class PersonOld
{
public int PersonId { get; set; }
public string PersonName { get; set; }
}
I might have to use reflection...
Thanks in advance
Below is a working example:
The main piece is the CreateMapping method, which just provides a delegate for converting from one type to another. Once you have that, copying source objects into a list of destination objects becomes trivial, as shown further below in my Fill method.
public static Func<T1, T2> CreateMapping<T1, T2>()
where T2 : new()
{
var typeOfSource = typeof(T1);
var typeOfDestination = typeof(T2);
// use reflection to get a list of the properties on the source and destination types
var sourceProperties = typeOfSource.GetProperties();
var destinationProperties = typeOfDestination.GetProperties();
// join the source properties with the destination properties based on name
var properties = from sourceProperty in sourceProperties
join destinationProperty in destinationProperties
on sourceProperty.Name equals destinationProperty.Name
select new { SourceProperty = sourceProperty, DestinationProperty = destinationProperty };
return (x) =>
{
var y = new T2();
foreach (var property in properties)
{
var value = property.SourceProperty.GetValue(x, null);
property.DestinationProperty.SetValue(y, value, null);
}
return y;
};
}
public static void Fill<T1, T2>(List<T1> Source, List<T2> Destination)
where T2 : new()
{
Destination.AddRange(Source.Select(CreateMapping<T1, T2>()));
}
You may take a look at AutoMapper.
As far as your utility method is concerned you must declare the generic arguments:
public class Utility
{
public static List<T2> Fill<T1, T2>(List<T1> Source, List<T2> Destination)
{
return null;
}
}
If using reflection, iterate through the source collection, instantiating instances of the target class. Insert these into a newly created list.
Next, Use GetProperties on the source type to get a collection of PropertyInfo classes. Iterate through these, picking out the name of each, and use Type.GetProperty to see if there is a property of the same name on the destination class. If so, use PropertyInfo.SetValue to set the value on each target object.
NB Need to do a bit more work if the properties are reference types - you'd need to consider whether you want to copy those types, or copy the reference
If the objects are identical, An alternative would be to serialise to and from XML.

Adding new T to empty List<T> using reflection

I'm attempting to set add a new instance of an Officer class to a potentially empty list using reflection.
These are my classes
public class Report(){
public virtual ICollection<Officer> Officer { get; set; }
}
public class Officer(){
public string Name{ get; set; }
}
Simplified code snippet:
Report report = new Report()
PropertyInfo propertyInfo = report.GetType().GetProperty("Officer");
object entity = propertyInfo.GetValue(report, null);
if (entity == null)
{
//Gets the inner type of the list - the Officer class
Type type = propertyInfo.PropertyType.GetGenericArguments()[0];
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(type);
entity = Activator.CreateInstance(constructedListType);
}
//The entity is now List<Officer> and is either just created or contains a list of
//Officers
//I want to check how many officers are in the list and if there are none, insert one
//Pseudo code:
if (entity.count = 0)
{
entity.add(new instance of type)
}
Much appreciated!
Use:
object o = Activator.CreateInstance(type); // "type" is the same variable you got a few lines above
((IList)entity).add(o);
You have two options:
1) Using dynamic:
dynamic list = entity;
if (list.Count = 0)
{
list.Add(new instance of type)
}
2) Using Reflection:
var countProp = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).First(p => p.Name == "Count");
var count = (int)countProp.GetValue(entity,null);
if(count == 0)
{
var method = entity.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public).First(m => m.Name == "Add");
method.Invoke(entity,new instance of type);
}
This isn't quite what you asked for but may accomplish the same task.
public static ICollection<T> EnsureListExistsAndHasAtLeastOneItem(ICollection<T> source)
where T : Officer, new()
{
var list = source ?? new List<T>();
if( list.Count == 0 ) list.Add(new T());
return list;
}
If Officer doesn't have a default constructor then you could add a factory callback
public static ICollection<T> EnsureListExistsAndHasAtLeastOneItem
(ICollection<T> source, Func<T> builder)
where T : Officer
{
var list = source ?? new List<T>();
if( list.Count == 0 ) list.Add(builder());
return list;
}
Just type your entity appropriately as a List<Officer> (or an appropriately more abstract type (such as IList)) and use as normal:
entity = Activator.CreateInstance(constructedListType) as IList;
But no need to check whether to insert or not, just insert:
entity.Insert(0, officer);
I'm assuming (based on the fact that you already know how to create instances using reflection) you're not having trouble creating the instance of type Officer.
Edit after re-reading over your question: This doesn't directly answer your question but is rather a suggestion of a different implementation.
You can easily get by without using reflection:
public class TestContainer<T>
{
private readonly List<T> _list;
public TestContainer()
{
_list = new List<T>();
}
public void Add()
{
_list.Add(default(T));
}
}
Then calling e.g.:
var t = new TestContainer<YourClass>();
t.Add();
t.Add();
t.Add();
you will have a list of 3 instances of YourClass by their default value

Categories