Introduction
Using Models view controller often requires converting the model from one type to another.
This is often done by assigning and manually casting type to another type.
In this article, we will learn how to generically and dynamically convert the model to another model using System.Reflection
and Attributes
.
Note: This code is writen on the spot, so there is no testing and the code has not been run.
Packages
In this article, we will use only one package and it's really optional: FastDeepCloner.
Using the Code
These are the test classes we will use in this example.
public class User
{
public string UserName { get; set; }
public string Email { get; set; }
public Person Person { get; set; } = new Person();
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserModelView
{
[PropertyCordinator("Person.FirstName$ $Person.LastName")]
public string Name { get; set; }
[PropertyCordinator("Email")]
public string UserEmail { get; set; }
public string UserName{ get; set; }
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class PropertyCordinator : Attribute
{
public readonly string PropertyPath;
public PropertyCordinator(string propertyPath)
{
PropertyPath = propertyPath;
}
}
Normally, converting class User
to UserModelView
will be as follows:
var user = new User()
{
UserName = "TAlen",
Email = "xxx@gmail.com",
Person = new Person()
{
FirstName = "Alen",
LastName = "Toma"
}
};
var userModel = new UserModelView()
{
UserEmail = user.Email,
Name = $"{user.Person.FirstName} {user.Person.LastName}"
};
Now let's create the converter.
public static T ToType<T>(this object item)
{
T model = (T)typeof(T).CreateInstance();
List<IFastDeepClonerProperty> props = FastDeepCloner.DeepCloner.
GetFastDeepClonerProperties(model.GetType());
foreach (var p in props)
{
var propertyCordinate = p.GetCustomAttribute<PropertyCordinator>();
string path = propertyCordinate?.PropertyPath ?? p.Name;
var value = GetPropertyValue(item, path);
if (value != null)
{
p.SetValue(model, value);
}
}
return model;
}
private static object GetPropertyValue(object item, string propertyName)
{
var names = propertyName.Split('$');
object result = null;
foreach (var name in names)
{
if (name == " ")
{
if (result == null)
result = " ";
else result = result + " ";
continue;
}
object rItem = item;
var subNames = name.Split('.');
foreach (var sn in subNames)
{
var p = FastDeepCloner.DeepCloner.GetFastDeepClonerProperties(rItem.GetType())
.FirstOrDefault(x =>
string.Equals(x.Name, sn, StringComparison.CurrentCultureIgnoreCase));
if (!p.IsInternalType)
{
rItem = p.GetValue(rItem);
}
else
{
var r = p.GetValue(rItem);
if (r == null)
continue;
if (r.GetType() == typeof(string))
{
if (result == null)
result = r;
else result = result.ToString() + r.ToString();
}
else
{
result = r; }
}
}
}
return result;
}
UserModelView model = user.ToType<UserModelView>()
Points of Interest
Using System.Reflection
makes programing more fun and also much less code to write.
I hope I was able to show that to you in this article.
Those kind of methods are often used by a big libraries like JsonParser
or even EntityFramework
.
History
- 25th October, 2018: Initial version