Reputation: 5375
Let's say I have multiple pairs of two different classes that have the exact same properties.
public class Class1
{
public int IntValue { get; set; }
public string StringValue { get; set; }
}
public class Class2
{
public int IntValue { get; set; }
public string StringValue { get; set; }
}
Is it possible to create a method that takes any object
as an argument and returns an object
where I pass in Class1
and it returns Class2
or vise versa without knowing what class will be passed in? We can assume that the two classes will share the exact same properties. We would need to define the Type
that we want returned when we call the method.
Upvotes: 1
Views: 644
Reputation: 8440
Yes, it is possible using reflection and iterating through each property. The only problem is when your class hides parameterless constructor, but then instead of creating this object inside the converter, you can pass it through parameter.
The solution below doesn't require both classes to contain the same properties.
using System;
using System.Linq;
namespace Utils
{
public static class TypeConverter
{
public static TDestination Convert<TSource, TDestination>(TSource source)
{
var destination = Activator.CreateInstance<TDestination>();
var destProperties = destination.GetType()
.GetProperties()
.ToDictionary(x => x.Name);
foreach (var prop in source.GetType().GetProperties())
{
if (destProperties.ContainsKey(prop.Name))
{
destProperties[prop.Name].SetValue(destination, prop.GetValue(source));
}
}
return destination;
}
}
}
Usage:
var c1 = new Class1() { IntValue = 1, StringValue = "aaaa" };
var c2 = TypeConverter.Convert<Class1, Class2>(c1);
Upvotes: 1
Reputation: 1
You only need to use System.Reflection and the use of Dictionaries for mapping data if you do something like.
public T ConvertClass<T>(X objectModel)
{
Dictionary<string,string> columnMapping = new Dictionary<string,string>
string valueTempplete = "'{value}'"
foreach(var prop in objectModel.GetType().GetProperties(BindingFlags))
{
var propertyName = prop.Name;
var value = objectModel.GetType().GetProperty(propertName).GetValue(objectModel, null).ToString();
columnMapping.Add(propertyName, valueTemplete.Replace("{value}",value))
}
}
The reason behind using the value template is so you don't create a new instance of the string every time you go into the loop. You will have to figure out a way to map the dictionary data to your T object. After you figure that out you can just pass in the class you want to convert to into the <>, and the object you are converting from into the parameter. I know this is not a complete answer but should give you a good start.
Upvotes: 0
Reputation: 43254
Assuming you can modify your code to have all the classes implement a common interface:
public interface SomeInterface
{
int IntValue { get; set; }
string StringValue { get; set; }
}
public class Class1 : SomeInterface
{
public int IntValue { get; set; }
public string StringValue { get; set; }
}
public class Class2 : SomeInterface etc
Then a simple method can be created to convert from one to the other:
public T1 Convert<T1, T2>(T2 source) where T1 : SomeInterface, T2 : SomeInterface
{
return new T1
{
IntValue = source.IntValue,
StringValue = source.StringValue
};
}
Then you use it in the following way:
var x = new Class1 { IntValue = 1, StringValue = "someText" };
...
Class2 y = Convert(x);
However a more practical solution would be to remove the multiple classes, all with the same structure, and replace them with a common one.
Upvotes: 1
Reputation: 152521
The only way without knowing the type at compile time would be to use reflection to:
Tools like AutoMapper do a decent job out-of-the-box, but almost always need some sort of custom configuration when mapping from one type to another.
If you have two types that have the exact same properties and types, then perhaps you need a base type for the common properties?
Upvotes: 6