c# - 如何深度复制强类型集合的成员

标签 c# .net reflection

我有两个类 XmlPerson 和 Person,每个类都有公共(public)属性,没有方法也没有任何字段。

我如何将所有属性从 Person 深度复制到 XmlPerson?我不想使用第三方库,如 MiscUtil.PropertyCopy 或 Automapper。我已经设法复制了原始类型和强类型对象的“第一级”属性,但是当它出现列表时我不知道。

Person类的结构如下:

public class Person
{
    public string FirstName { get; set; }

    public string Surname { get; set; }

    public decimal? Salary { get; set; }

    public List<AddressDetails> AddressDetails { get; set; }

    public NextOfKin NextOfKin { get; set; }
}

public class NextOfKin
{
    public string FirstName { get; set; }

    public string Surname { get; set; }

    public string ContactNumber { get; set; }

    public List<AddressDetails> AddressDetails { get; set; }
}

public class AddressDetails
{
    public int HouseNumber { get; set; }

    public string StreetName { get; set; }

    public string City { get; set; }
}

谢谢你的帮助。 查尔斯

这是我目前所拥有的:

公共(public)类 XmlTestCaseToClassMapper { 内部 TTarget MapXmlClassTotargetClass(TSource xmlPerson) { var targetObject = Activator.CreateInstance(); var sourceObject = Activator.CreateInstance();

        //var xmlClassProperties = xmlPerson.GetType().GetProperties().ToList().OrderBy(x => x.Name);

        var xmlClassProperties = GetProperties(xmlPerson.GetType());

        //var targetClassProperties = targetObject.GetType().GetProperties().ToList().OrderBy(x => x.Name);

        var targetClassProperties = GetProperties(targetObject.GetType());

        PropertyInfo targetClassProperty = null;

        foreach (var xmlProperty in xmlClassProperties)
        {
            if (!xmlProperty.PropertyType.IsClass || xmlProperty.PropertyType.UnderlyingSystemType == typeof(string)
                || xmlProperty.PropertyType.IsPrimitive)
            {
                targetClassProperty = targetClassProperties.ToList().FirstOrDefault(x => x.Name == xmlProperty.Name);

                var propertyValue = xmlProperty.GetValue(xmlPerson, null);

                targetClassProperty.SetValue(targetObject, propertyValue, null);
            }

            else if (xmlProperty.PropertyType.UnderlyingSystemType == typeof(NextOfKin)) //Check subType of the property
            {
                var subPropertyInstance = Activator.CreateInstance(xmlProperty.GetType());
                var subProperties = GetProperties(xmlProperty.GetType());

                subProperties.ForEach(subProperty =>
                {
                    targetClassProperty = targetClassProperties.ToList().FirstOrDefault(x => x.Name == subProperty.Name && x.GetType().IsClass);
                    targetClassProperty.SetValue(subPropertyInstance, xmlProperty.GetValue(this, null), null);
                });
            }

            //else if (xmlProperty.PropertyType.IsGenericType)

            //{

            //        var xmlGenericType = xmlProperty.PropertyType.GetGenericArguments().First();

            //        var xmlGenericTypeProperties = GetProperties(xmlGenericType);

            //        targetClassProperty = targetClassProperties.ToList().FirstOrDefault(x => x.Name == xmlProperty.Name);

            //        var targetGenericType = targetClassProperty.PropertyType.GetGenericArguments().First();

            //        var targetGenericProperties = GetProperties(targetGenericType);

            //        Type targetGenericList = typeof(List<>).MakeGenericType(new Type[] { targetGenericType });

            //        object listInstance = Activator.CreateInstance(targetGenericList);

            //    //foreach (var xmlGenericProperty in xmlGenericTypeProperties)

            //    //{

            //    //    var targetGenericProperty = targetGenericProperties.FirstOrDefault(x => x.Name == xmlGenericProperty.Name);

            //    //    targetGenericProperty.SetValue(targetGenericProperty, xmlGenericProperty.GetValue(xmlGenericType, null), null);

            //    //}

            //    xmlGenericTypeProperties.ForEach(x =>

            //    {

            //        foreach (var targetGenericProperty in targetGenericProperties)

            //        {

            //            targetGenericProperty.SetValue(targetGenericProperty, targetGenericProperty.GetValue(x, null), null);

            //        }

            //    });

            //}

            //}

        }
        return targetObject;
    }

    private List<PropertyInfo> GetProperties(Type targetType)
    {
        var properties = new List<PropertyInfo>();

        targetType.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList().ForEach(property =>
        {

            properties.Add(property);

        });

        return properties.OrderBy(x => x.Name).ToList();
    }
}

最佳答案

这是一个可能的解决方案。它可能需要根据您的实际类(class)进行一些调整。

public T DeepCopy<S, T>(S source) where T : new()
{
    var sourceProperties = typeof(S).GetProperties(BindingFlags.Instance | BindingFlags.Public);
    T target = new T();

    foreach (var sourceProperty in sourceProperties)
    {
        var property = typeof(T).GetProperty(sourceProperty.Name);

        if (property.PropertyType.IsPrimitive || 
            property.PropertyType == typeof(string) || 
            (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
        {
            object value = sourceProperty.GetValue(source);

            property.SetValue(target, value);
        }
        else if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
        {
            var sourceList = (IEnumerable)sourceProperty.GetValue(source);

            if (sourceList != null)
            {
                var deepCopy = this.GetType().GetMethod("DeepCopy").MakeGenericMethod(sourceProperty.PropertyType.GenericTypeArguments[0], property.PropertyType.GenericTypeArguments[0]);
                var ctor = property.PropertyType.GetConstructor(Type.EmptyTypes);

                IList targetList = (IList) ctor.Invoke(null);

                foreach (var element in sourceList)
                {
                    targetList.Add(deepCopy.Invoke(this, new object[] { element } ));
                }

                property.SetValue(target, targetList);
            }
        }
        else
        {
            var value = sourceProperty.GetValue(source);

            if (value != null)
            {
                var deepCopy = this.GetType().GetMethod("DeepCopy").MakeGenericMethod(sourceProperty.PropertyType, property.PropertyType);

                property.SetValue(target, deepCopy.Invoke(this, new object[] { value }));
            }
        }
    }

    return target;
}

关于c# - 如何深度复制强类型集合的成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19541420/

相关文章:

c# - 检查表达式是否有自由参数

c# - 在没有显式引用的情况下调用方法的扩展方法

c# - 在 app.config 中使用 XML 包含或配置引用来包含其他配置文件的设置

.net - 流多播 - 一次读取一个流,但以不同的方式处理它,缓冲最少

c# - 插件应用程序出现转换错误

c# - 是否有可能让一个类(class)了解自己是否使用了反射?

C#/Mono Console.In.ReadToEnd() 停止进程

c# - 在 c# 中将 int 添加到 char 以将其 ascii 值向上移动(就像在 c++ 中一样)

c# - 错误 - 403 禁止 - Microsoft-Azure-Application-Gateway/v2

java - 如何在Java中创建通用数组?