I have now several times found myself in the peculiar situation of having two classes, that mostly have the same properties and fields, but doesn't implement the same interface or inherit from the same ancestor, which makes it rather tedious to convert between them.
The problem is typically seen when dynamically loading 3rd party libraries and trying to get them to interact with other 3rd party libraries, or when doing some advanced kinds of communication (like WCF) with complex types.
True, in some cases the problems can be avoided totally by considering your data, assembly and communication structure - but still there's those hopeless cases where you find yourself writing yet another "Create an object of this type based on that type"-code piece. Not a difficult task, but boring.
So, as always I've tried to come up with a stupid solution to a stupid problem: A Generic Type Converter. It uses Generics to "convert" type A to type B. By Converting it simply matches up the public properties and fields and copies the ones that match and that it's allowed to.
Sure, it might be slow (and some might even find it ugly) - but for tasks where the development time is more critical than a few miliseconds of execution time (like for POC's) it might be a nice thing to have in your toolbox.
Keep in mind that this is just a draft version 0.0.0.01.
P.S. Sorry about the formatting, but I'm having a small war with my blogspot and some CSS :-)
using System.Reflection;
public static class GenericTypeConverter
{
public static DestType ConvertType<SrcType, DestType>(SrcType Source) where DestType:class,new()
{
return ConvertType<SrcType,DestType>(Source, null, null);
}
public static DestType ConvertType<SrcType, DestType>(SrcType Source, Dictionary<string, string> SrcDestMapping) where DestType : class,new()
{
return ConvertType<SrcType,DestType>(Source, SrcDestMapping,null);
}
private static string GetMappedName(Dictionary<string, string> Map, string OrigName)
{
if((Map!=null)&&(Map.ContainsKey(OrigName))) return Map[OrigName];
return OrigName;
}
/// <summary>
/// Uses reflection to convert an object to a destination type, e.g. transfers all the properties and members they have in common
/// </summary>
/// <typeparam name="SrcType">Source Type</typeparam>
/// <typeparam name="DestType">Destination Type</typeparam>
/// <param name="Source">Object to convert</param>
/// <param name="SrcDestMap">Mapping between source and destination property names. Null if no mapping exist.</param>
/// <param name="Dest">Destination object or null if it should be created</param>
/// <returns>An object where as many properties and fields as possible have been transferred from Source.</returns>
private static DestType ConvertType<SrcType, DestType>(SrcType Source, Dictionary<string, string> SrcDestMap, DestType Dest) where DestType : class
{
//Create object if it doesn't exist.
DestType dstVar = Dest;
if (dstVar == null) dstVar = Activator.CreateInstance<DestType>();
//Loop through Source' public properties
Type srcTp = typeof(SrcType);
PropertyInfo[] props=srcTp.GetProperties(System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.GetProperty);
foreach (PropertyInfo p in props)
{
//Check if destination type has a settable property of the same type
PropertyInfo pDest = typeof(DestType).GetProperty(GetMappedName(SrcDestMap,p.Name), p.PropertyType);
if ((pDest != null) && (pDest.CanWrite)) pDest.SetValue(dstVar, p.GetValue(Source, null), null);
}
//Loop through Source' public fields
FieldInfo[] mems=srcTp.GetFields();
foreach (FieldInfo fi in mems)
{
FieldInfo mDest = typeof(DestType).GetField(GetMappedName(SrcDestMap,fi.Name));
if ((mDest != null) && (fi.FieldType == mDest.FieldType))
{
mDest.SetValue(dstVar, fi.GetValue(Source));
}
}
return dstVar;
}
}