garry man
garry man

Reputation: 465

Deep copy object properties (including those with private setter) to another object of the same type

I have done some research and only found "superficial" methods that actually copy your properties from one object to another, such as:

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

The problem with the above method is that it doesn't copy the private fields too.

I have a class like this:

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

Now let's suppose I will run the above method on these two classes:

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

The outcome will be that obj2.flag value will remain unchanged`.

I am looking for a method that actually deep copies all properties including those with private setters.

Upvotes: 2

Views: 1338

Answers (1)

Luke Caswell Samuel
Luke Caswell Samuel

Reputation: 463

This is because Type.GetProperties only returns properties. What you are searching for is essentially the same code as the CopyPropertiesTo above, but you want to replace GetProperties with GetFields. You also need to specify BindingFlags in the parameters of the method to get private members.

Try this out:

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

Upvotes: 1

Related Questions