vendredi 25 décembre 2020

Reflection - How to copy common properties from one class to another when there are subclasses

I'm working on a c# application and trying to make this code working. It fails when it tries to copy a property which is a list of a subclass object. I'm able to check the common properties in both classes and the code works fine for most types I've used, even List<string>. When I have properties of type e.g. List<SubClass>it fails. The code fails also for simple objects of the Subclass.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Questions
{
    class Program
    {
        static void Main(string[] args)
        {
            Class1 class1 = new Class1
            {
                Prop1 = "X",
                List1 = new List<Class1.SubClass>
                {
                    new Class1.SubClass { SubProp1 = "A", SubProp2 = "B" }
                }
            };

            Class2 class2 = class1.CopyTo<Class2>();    //---> fails when it tries to SetValue for the List<SubClass>
        }
    }

    public class Class1
    {
        public string Prop1 { get; set; }
        public List<SubClass> List1 { get; set; }

        public string Prop3 { get; set; }

        public class SubClass
        {
            public string SubProp1 { get; set; }
            public string SubProp2 { get; set; }
        }
    }

    public class Class2
    {
        public string Prop1 { get; set; }
        public List<SubClass> List1 { get; set; }

        public string Prop4 { get; set; }

        public class SubClass
        {
            public string SubProp1 { get; set; }
            public string SubProp2 { get; set; }
        }
    }

    public static class Extensions
    {
        public static T CopyTo<T>(this Object sourceObject) 
        {
            Type sourceObjectType = sourceObject.GetType();
            Type targetType = typeof(T);
            var targetInstance = Activator.CreateInstance(targetType, false);

            List<PropertyInfo> identicalProperties = new List<PropertyInfo>();

            var propertiesTarget = typeof(T).GetProperties();
            var propertiesSource = sourceObject.GetType().GetProperties();

            foreach (var s_property in propertiesSource)
            {
                foreach (var t_property in propertiesTarget)
                {
                    if (s_property.Name.Equals(t_property.Name))
                    {
                        identicalProperties.Add(s_property);
                        continue;
                    }
                }
            }

            object value;

            foreach (PropertyInfo property in propertiesTarget)
            {
                var res = identicalProperties.Any(x=>x.Name.Equals(property.Name));
                if (!res)
                {
                    continue;
                }
                value = sourceObjectType.GetProperty(property.Name).GetValue(sourceObject, null);
                property.SetValue(targetInstance, value, null);
            }

            return (T)targetInstance;
        }
    }
}

I assume this is achievable but I'm struggling to find a way to identify the type of property and when to cast the value to the correct type here property.SetValue(targetInstance, value, null);. value should probably be casted as a List. The error thrown by the compiler is: System.ArgumentException: 'Object of type 'System.Collections.Generic.List1[Questions.Class1+SubClass]' cannot be converted to type 'System.Collections.Generic.List1[Questions.Class2+SubClass]'

Can anyone help? Much appreciated.





Aucun commentaire:

Enregistrer un commentaire