Конвертировать объект по отражению

Я хочу преобразовать объект A в объект B. Классы A и B имеют одинаковые свойства, только имена меняются.

Я использую этот метод:

 /// <summary>

    internal static T objectMapper<T>(object objectSource, T objectTarget)
    {
        dynamic o = objectSource;

        Type typeA = objectSource.GetType();
        Type typeB = objectTarget.GetType();
        IList<PropertyInfo> propsA = new List<PropertyInfo>(typeA.GetProperties());
        IList<PropertyInfo> propsB = new List<PropertyInfo>(typeB.GetProperties());


        dynamic s;

        ArrayList listArray = new ArrayList();

        foreach (var prop in propsA)
        {
            s = objectSource.GetType().GetProperty(prop.Name).GetValue(objectSource, null);
            listArray.Add(s);
        }
        int i = 0;
        foreach (var prop in propsB)
        {
            prop.SetValue(objectTarget, listArray[i], null);
            i++;
        }
        return objectTarget;


    }

Как я могу редактировать свойства objectB в foreach цикл? Я хочу использовать универсальный метод для разных объектов.

3 ответа

Это решение обеспечивает как ваш путь отражения, так и альтернативный способ, определяя и реализуя метод копирования. CopyFrom, Чтобы сократить код, вы можете сделать интерфейс базовым классом, чтобы вам не нужно было реализовывать CopyFrom в подклассах....

public interface MyInterface
{
    int Prop1 { get; set; }
    string Prop2 { get; set; }
    void CopyFrom(MyInterface obj);
}

public class A: MyInterface
{
    public int Prop1 { get; set; }
    public string Prop2 { get; set; }
    public void CopyFrom(MyInterface obj)
    {
        this.Prop1 = obj.Prop1;
        this.Prop2 = obj.Prop2;
    }
}
public class B: MyInterface
{
    public int Prop1 { get; set; }
    public string Prop2 { get; set; }
    public void CopyFrom(MyInterface obj)
    {
        this.Prop1 = obj.Prop1;
        this.Prop2 = obj.Prop2;
    }
}

public static class CopyUtils
{
    public static void Copy(MyInterface src, MyInterface dst)
    {
        var props = typeof(MyInterface).GetProperties();
        foreach(var prop in props)
        {
            prop.SetValue(dst, prop.GetValue(src, null), null);
        }        
    }
}

Я чувствую, что здесь может быть более глубокая проблема архитектуры. Я не представляю, почему вы хотите "скопировать" значения свойств из одного объекта класса в другой класс с теми же именами свойств.

Если вы пытаетесь "придать форму" объекту, возможно, просто передайте интерфейс.

В любом случае, посмотрите, поможет ли это:

public static class ObjectMorpher
{
    public class InvalidMorphException : Exception
    {
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class IgnoredOnMorphAttribute : Attribute
    {

    }

    public static TargetType Morph<TargetType>(this object source, TargetType dest, Func<string, string> propertyMatcher = null, bool failOnNoMatch = false)
        where TargetType : class
    {
        if (source == null || dest == null)
            throw new ArgumentNullException();
        foreach (var sourceProp in source.GetType().GetProperties().Where(x => x.GetCustomAttributes<IgnoredOnMorphAttribute>().Any() == false))
        {
            var destProp = typeof(TargetType).GetProperties().Where(x => x.Name == ((propertyMatcher == null) ? sourceProp.Name : propertyMatcher(sourceProp.Name))).FirstOrDefault();
            //check property exists
            if (destProp == null)
            {
                if (failOnNoMatch)
                    throw new InvalidMorphException();
                else
                    continue;
            }
            //check value type is assignable
            if (!destProp.GetType().IsAssignableFrom(sourceProp.GetType()))
            {
                if (failOnNoMatch)
                    throw new InvalidMorphException();
                else
                    continue;
            }
            destProp.SetValue(dest, sourceProp.GetValue(source));
        }
        return dest;
    }
}

Пример использования:

var A = new ClassA();
var B = new ClassB();
B = A.Morph(B);

При желании вы можете установить соответствие свойств для случая, когда свойства не имеют одно и то же имя. Также обратите внимание на использование атрибута IgnoredOnMorph, чтобы пометить свойства как недоступные для изменения (например, вычисляемые свойства)

Вы можете найти автоматическое использование здесь (см. https://github.com/AutoMapper/AutoMapper/wiki/Getting-started).

Вам нужно создать строку для каждого сопоставления объекта в файле запуска, чтобы настроить его, но если свойства будут одинаковыми, это будет так просто:

mapper.CreateMap<ClassA, ClassB>().ReverseMap();

И затем одна строка для разрешения сопоставления при необходимости

mapper.Map(objectOfClassA, new ClassB());
Другие вопросы по тегам