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

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

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

10-07 13:22