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?
source to share
You can use AutoMapper to achieve this.
Mapper.CreateMap<ModelMetaData , ExtendedModelMetadata>();
The .NET Framework does not provide a deep copy feature.
source to share
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.
source to share
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.
}
}
source to share