Click here to Skip to main content
15,888,293 members
Articles / Programming Languages / C#
Tip/Trick

Convert From Type to Type using System Reflection

Rate me:
Please Sign up or sign in to vote.
4.08/5 (6 votes)
25 Oct 2018CPOL 14.1K   7   3
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.

C#
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:

C#
 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.

C#
        /// <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;
        }
C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Sweden Sweden
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseGood Pin
Alessandro Cavalieri26-Oct-18 4:27
Alessandro Cavalieri26-Oct-18 4:27 
GeneralMy vote of 5 Pin
szederbuci26-Oct-18 0:25
szederbuci26-Oct-18 0:25 
GeneralRe: My vote of 5 Pin
Alen Toma26-Oct-18 0:34
Alen Toma26-Oct-18 0:34 
thx

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.