views:

124

answers:

1

I think there's good no answer but before I throw in the towel on doing this gracefully I'll ask here:

I have a parent class which holds a bunch of data. These are used only to instantiate a descendant which takes the parent, modifies it and produces the final result.

I see how to use MemberwiseCopy to make another instance of the parent but I need a child, not another parent.

I see two answers, neither of which I like:

1) Forget inheritance, make a copy of the parent in a field in the working copy.

2) Copy each field to the child.

+2  A: 

Using reflection and custom attributes maybe? Decorate the fields you wish to copy to the descendant, and during the instantiation use reflection to go over each decorated field and copy its value to the descendant.

Example:

[AttributeUsage(AttributeTargets.Field)]
class PassDownAttribute : Attribute
{
}

public class TheParent
{
    [PassDown]
    public int field1;
    [PassDown]
    public string field2;
    [PassDown]
    public double field3;

    public int field4; // Won't pass down.

    public TheChild CreateChild()
    {
        TheChild x = new TheChild();
        var fields = typeof(TheParent).GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
        foreach (var field in fields)
        {
            var attributes = field.GetCustomAttributes(typeof(PassDownAttribute), true);
            if (attributes.Length == 0) continue;
            var sourceValue = field.GetValue(this);
            var targetField = typeof(TheChild).GetField(field.Name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            if (targetField != null)
                targetField.SetValue(x, sourceValue);
        }
        return x;
    }
}

public class TheChild
{
    public int field1;
    public string field2;
    public double field3;
}

And the usage:

public void TestIt()
{
    TheParent p = new TheParent
    {
        field1 = 5,
        field2 = "foo",
        field3 = 4.5,
        field4 = 3
    };
    TheChild c = p.CreateChild();
    Debug.Assert(c.field1 == p.field1);
    Debug.Assert(c.field2 == p.field2);
    Debug.Assert(c.field3 == p.field3);
}
Aviad P.