Can I get a "copy constructor" in C # that copies from a derived class?

An example application to illustrate my immediate problem:

I have a metadata provider class with the following (shorthand) interface:

public class CtsDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        return metadata;
    }
}

      

Now I would like to extend ModelMetadata

additional properties, fill them in and return and an instance ExtendedModelMetadata

. How can I pass properties assigned to an instance metadata

to base.CreateMetadata

in my extended instance? What I would like, but do not have, is

var metadata = (ExtendedModelMetadata)base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

      

I can create a constructor for ExtendedModelMetadata

that takes a parameter ModelMetadata

and explicitly assigns all of its properties to the instance being instantiated, but for that I need more general and less rigid code. What can I do?

+3


source to share


3 answers


You can use AutoMapper to achieve this.

Mapper.CreateMap<ModelMetaData , ExtendedModelMetadata>();

      



The .NET Framework does not provide a deep copy feature.

+3


source


You can use reflection and generics (this is a cheap, homemade example that copies all fields, it makes a few assumptions for brevity):

    class Program
    {
        static void Main(string[] args)
        {
            Base b = new Base();
            b.Number = 42;

            Derived d = Copy<Derived, Base>(b);
            Console.Read();
        }

        static TDerived Copy<TDerived, TBase>(TBase b)
            where TDerived : TBase, new()
        {
            TDerived d = new TDerived();

            var bType = typeof(TBase);
            var bFields = bType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            
            foreach (var field in bFields)
            {
                object val = field.GetValue(b);
                field.SetValue(d, val);
            }

            return d;
        }
    }

    class Base
    {
        public int Number { get; set; }
    }

    class Derived : Base
    {
        public string Name { get; set; }
    }

      



This assumes the type has a parameterless constructor without parameters, but you get the idea.

Alternatively, if performance is an issue, you can do something like create a code generator that encodes the assignment code using partial classes.

+2


source


I could separate creation and population if possible.

public class CtsDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var extended = new ExtendedModelMetadata();
        PopulateMetadata(extended, attributes, containerType, modelAccessor, modelType, propertyName);

        return extended ;
    }

    protected override void PopulateMetadata(ModelMetaData data, IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
         base.PopulateMetaData(data, attributes, containerType, modelAccessor, modelType, propertyName);

        //populate extended properties.
    }
}

      

+1


source







All Articles