Глубокое копирование свойств объекта (включая свойства с закрытым сеттером) в другой объект того же типа - PullRequest
0 голосов
/ 10 декабря 2018

Я провел некоторые исследования и нашел только «поверхностные» методы, которые фактически копируют ваши свойства из одного объекта в другой, такие как:

public static void CopyPropertiesTo<T, TU>(this T source, TU dest)
{
    var sourceProps = typeof(T).GetProperties().Where(x => x.CanRead).ToList();
    var destProps = typeof(TU).GetProperties()
        .Where(x => x.CanWrite)
        .ToList();
    foreach (var sourceProp in sourceProps)
    {
        if (destProps.Any(x => x.Name == sourceProp.Name))
        {
            var p = destProps.First(x => x.Name == sourceProp.Name);
            if (p.CanWrite)
            { // check if the property can be set or no.
                p.SetValue(dest, sourceProp.GetValue(source, null), null);
            }
        }
    }
}

Проблема с методом выше в том, что он тоже не копирует приватные поля .

У меня есть такой класс:

class myType{
    public object prop1;
    private bool flag;
    private otherType prop2; //recursive deep property copy loop needed on this object.

    myType(bool flag){
        this.flag = flag;
    }
}

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

myType obj1 = new myType(false);
myType obj2 = new myType(true);
obj1.CopyPropertiesTo(obj2);

В результате будет obj2.flag значение останется неизменным `.

Я ищу метод, который на самом деле deep копирует все свойства, включая свойства с закрытыми сеттерами.

1 Ответ

0 голосов
/ 10 декабря 2018

Это потому, что Type.GetProperties возвращает только свойства.По сути, вы ищете тот же код, что и CopyPropertiesTo выше, но вы хотите заменить GetProperties на GetFields.Вам также нужно указать BindingFlags в параметрах метода, чтобы получить приватных членов.

Попробуйте это:

public static void CopyFieldsTo<T, TU>(this T source, TU dest)
{
    var sourceFields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList();
    var destFields = typeof(TU).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList();
    foreach (var sourceField in sourceFields)
    {
        if (destFields.Any(x => x.Name == sourceField.Name))
        {
            var f = destFields.First(x => x.Name == sourceField.Name);
            f.SetValue(dest, sourceField.GetValue(source));
        }
    }
}
...