Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Convert From Type to Type using System Reflection

0.00/5 (No votes)
25 Oct 2018 1  
Convert From Type to Type using System reflection

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; }
}

/// <summary>
/// This is the modelView that will contain data from both User and Person
/// </summary>
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; }
}

/// <summary>
/// This attribute is to map a property from One type to another type
/// </summary>
[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"
     }
 };

// now converting this to UserModelView will usually be like this
 var userModel = new UserModelView()
 {
     UserEmail = user.Email,
     Name = $"{user.Person.FirstName} {user.Person.LastName}"
 };
// we will learn to make this much easier by using System.Reflection
// like user.ToType<UserModelView>();

Now let's create the converter.

        /// <summary>
        ///  Convert type of class to another type
        ///  this method cannot handle IList yet, you need to further develop it to use IList
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static T ToType<T>(this object item)
        {
            T model = (T)typeof(T).CreateInstance();
            // using FastDeepcloner is much faster then 
            // item.GetType().GetProperties(), because it has caching mechanism.
            List<IFastDeepClonerProperty> props = FastDeepCloner.DeepCloner.
            GetFastDeepClonerProperties(model.GetType());

            foreach (var p in props)
            {
                var propertyCordinate = p.GetCustomAttribute<PropertyCordinator>();
                // if we have PropertyCordinator, then take it or assume the name property itself
                string path = propertyCordinate?.PropertyPath ?? p.Name;
                var value = GetPropertyValue(item, path);
                if (value != null)
                {
                    // There is no type converting in this case, 
                    // for further developing where different propertytypes 
                    // exist, we may need to convert the value
                    p.SetValue(model, value);
                }
            }
            return model;
        }

        /// <summary>
        ///  Get the value by its path
        /// </summary>
        /// <param name="item"></param>
        /// <param name="propertyName"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        private static object GetPropertyValue(object item, string propertyName)
        {
            // try to split Person.FirstName$ $Person.LastName
            var names = propertyName.Split('$');
            object result = null;

            foreach (var name in names)
            {
                if (name == " ") // add the space
                {
                    if (result == null)
                        result = " ";
                    else result = result + " ";

                    continue;
                }

                object rItem = item;
                /// try to split Person.FirstName
                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) // e.g., Is class. Is Person Object or string FirstName
                    {
                        // We need to prepare when cases like Item is an Ilist,
                        // but we will skip this for this article.
                        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; /// other types like Int, DateTime and so on.
                        }
                    }
                }
            }

            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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here