Currently I have custom mapper that accepts a TSource
and a TDestination
;
Edit to clarify: I want to pass var refobj= System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(sourcename);
to MapToList<TSource, TDestination>
as a replacement for TSource
.
public static TDestination Map<TSource, TDestination>(TSource sourceObject)
{
var destinationObject = Activator.CreateInstance<TDestination>();
if (sourceObject != null)
{
foreach (var sourceProperty in typeof(TSource).GetProperties())
{
var destinationProperty = typeof(TDestination).GetProperty(sourceProperty.Name);
destinationProperty?.SetValue(destinationObject, sourceProperty.GetValue(sourceObject));
}
}
return destinationObject;
}
This is fine until it encounters a List
. So I extended the mapper like this
public static TDestination Map<TSource, TDestination>(TSource sourceObject)
{
var destinationObject = Activator.CreateInstance<TDestination>();
if (sourceObject != null)
{
foreach (var sourceProperty in typeof(TSource).GetProperties())
{
var destinationProperty = typeof(TDestination).GetProperty(sourceProperty.Name);
If (//check for list)
{
var sourcename = sourceProperty.ReflectedType?.FullName;
var refobj= System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(sourcename);
destinationProperty?.SetValue(destinationObject, MapToList<refobj, //destinationRefObj>(listToMap));
}
destinationProperty?.SetValue(destinationObject, sourceProperty.GetValue(sourceObject));
}
}
return destinationObject;
}
Mapping the list.
private static List<TDestination> MapToList<TSource, TDestination>(List<TSource> source)
{
var target = new List<TDestination>(source.Count);
foreach (var item in source)
{
//DOMAP
}
return target;
}
How can I instantiate a class so I can use it to pass to MapToList<TSource, TDestination>
? I can't use the reflected object for that because the error is "refobj is a variable but is used like a type". Thanks
Putting aside why you implement custom mapper, when there are many solutions available, you can try following:
public static class Mapper
{
public static TDestination Map<TSource, TDestination>(TSource sourceObject)
{
var destinationObject = Activator.CreateInstance<TDestination>();
if (sourceObject != null)
{
foreach (var sourceProperty in typeof(TSource).GetProperties())
{
var destinationProperty = typeof(TDestination).GetProperty(sourceProperty.Name);
var sourceValue = sourceProperty.GetValue(sourceObject);
object mapped;
if (sourceValue.IsGenericList())
{
mapped = MapToList(sourceProperty.PropertyType.GenericTypeArguments.Single(),
destinationProperty.PropertyType.GenericTypeArguments.Single(), sourceValue);
}
else
{
mapped = Map(sourceProperty.PropertyType,
destinationProperty.PropertyType, sourceValue);
}
destinationProperty?.SetValue(destinationObject, mapped);
}
}
return destinationObject;
}
private static object Map(Type sourceType, Type destinationType, object value)
{
if (destinationType.IsAssignableFrom(sourceType))
{
return value;
}
var genericMap = typeof(Mapper).GetMethod(nameof(Map), BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(sourceType, destinationType);
return genericMap.Invoke(null, new[] { value });
}
private static object MapToList(Type sourceType, Type destinationType, object value)
{
var genericMapToList = typeof(Mapper).GetMethod(nameof(MapToList), BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(sourceType, destinationType);
return genericMapToList.Invoke(null, new []{value});
}
private static List<TDestination> MapToList<TSource, TDestination>(List<TSource> source)
{
var target = new List<TDestination>(source.Count);
var addMethod = target.GetType().GetMethod("Add");
foreach (var item in source)
{
var mappedObj = Map(typeof(TSource), typeof(TDestination), source);
addMethod.Invoke(target, new object[] { mappedObj });
}
return target;
}
public static bool IsGenericList(this object o)
{
var oType = o.GetType();
return (oType.IsGenericType && (oType.GetGenericTypeDefinition() == typeof(List<>)));
}
}
I hope I got it right now, it is a bit more complex problem and this code doesn't have many checks on null etc.
for the generic list check I used: https://stackoverflow.com/a/794257/9855767