Reputation: 1569
I am trying to convert a class to another class using the Mapper
class, It works for the non-user-defined types when it comes to user-defined types, It's showing an Exception.
Unhandled Exception: System.ArgumentException: Object of type
'DataModal.TblBook'
cannot be converted to type'DomainModal.Book'
. at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast) at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
I have tried Creating a new Generic Method
during runtime using this answer How do I use reflection to call a generic method?
in TblStudent.cs
the type is of TblBook
and in Student.cs
the type is of Book
I am unable to convert it.
But I am failing to convert it.
Here is my Mapper.cs
using DomainModal;
using DataModal;
using System.Linq;
using System;
using System.Reflection;
namespace DataAccessLogic
{
public class Mapper<T, U> where U : new()
{
public U Convert(T input)
{
U newCastType = new U();
var fromObjectProperties = input.GetType().GetProperties();
var toObjectProperties = newCastType.GetType().GetProperties();
foreach (var parentProperty in fromObjectProperties)
{
foreach (var childProperty in toObjectProperties)
{
if (parentProperty.Name == childProperty.Name)
{
childProperty.SetValue(newCastType, parentProperty.GetValue(input));
}
}
}
/*var fromObjectProperties = input.GetType().GetProperties();
foreach (var parentProperty in fromObjectProperties)
{
}*/
return newCastType;
}
}
}
TblStudent.cs
using System;
namespace DataModal
{
public class TblStudent
{
public string EmailId { get; set; }
public string Password { get; set; }
public string StudentName { get; set; }
public string StudentId { get; set; }
public string PhoneNumber { get; set; }
public TblBook GetBook { get; set; }
}
}
Student.cs
using System;
namespace DomainModal
{
public class Student
{
public string EmailId { get; set; }
public string Password { get; set; }
public string StudentName { get; set; }
public string StudentId { get; set; }
public string PhoneNumber { get; set; }
public Book GetBook { get; set; }
}
}
Full Source Code here: https://gitlab.com/chintuyadavsara/console-application
I don't know Where I am doing wrong. Any help will be appreciated
Thank you.
Upvotes: 0
Views: 639
Reputation: 17485
You can do something like this.
public class Mapper<T, U> where U : new()
{
public U Convert(T input)
{
U newCastType = new U();
var fromObjectProperties = input.GetType().GetProperties();
var toObjectProperties = newCastType.GetType().GetProperties();
foreach (var parentProperty in fromObjectProperties)
{
foreach (var childProperty in toObjectProperties)
{
if((parentProperty.Name == childProperty.Name) && parentProperty.PropertyType.IsClass && parentProperty.PropertyType.Name != "String")
{
var typeInfo = typeof(Mapper<,>);
var genericType = typeInfo.MakeGenericType(parentProperty.PropertyType, childProperty.PropertyType);
var genericMethodInfo = genericType.GetMethod("Convert");
var ojb = Activator.CreateInstance(genericType);
var targetValue = genericMethodInfo.Invoke(ojb, new[] { parentProperty.GetValue(input) });
childProperty.SetValue(newCastType, targetValue);
}
else if ((parentProperty.Name == childProperty.Name))
{
childProperty.SetValue(newCastType, parentProperty.GetValue(input));
}
}
}
/*var fromObjectProperties = input.GetType().GetProperties();
foreach (var parentProperty in fromObjectProperties)
{
}*/
return newCastType;
}
}
Upvotes: 1
Reputation: 2619
Example by using Reflection to recursively call the generic method on the properties which are not of the same Type
(but have the same name):
public class Mapper
{
public static TRes Convert<TIn, TRes>(TIn obj)
{
TRes targetInstance = Activator.CreateInstance<TRes>();
var sourceTypePropertyInfos = obj.GetType().GetProperties();
var targetTypePropertyInfos = targetInstance.GetType().GetProperties();
foreach (var sourceTypePropertyInfo in sourceTypePropertyInfos)
{
foreach (var targetTypePropertyInfo in targetTypePropertyInfos)
{
if (sourceTypePropertyInfo.Name == targetTypePropertyInfo.Name)
{
if (sourceTypePropertyInfo.PropertyType == targetTypePropertyInfo.PropertyType)
{
targetTypePropertyInfo.SetValue(targetInstance, sourceTypePropertyInfo.GetValue(obj));
}
else
{
var sourcePropertyValue = sourceTypePropertyInfo.GetValue(obj);
var methodInfo = typeof(Mapper).GetMethod(nameof(Mapper.Convert));
var genericMethodInfo = methodInfo.MakeGenericMethod(sourceTypePropertyInfo.PropertyType, targetTypePropertyInfo.PropertyType);
var targetValue = genericMethodInfo.Invoke(new Mapper(), new[] { sourcePropertyValue });
targetTypePropertyInfo.SetValue(targetInstance, targetValue);
}
}
}
}
return targetInstance;
}
}
Call it as:
var student = Mapper.Convert<TblStudent, Student>(tblStudent);
Upvotes: 2