Using AutoMapper to map complex classes with members that are hidden behind an interface
I recently wanted to use AutoMapper (a .NET library for mapping objects of one type to another) to map class containing many properties that were of a type that also needed to be mapped to another, similar type. To make matters worse, the type that I wanted to map to didn't just have properties of a custom type, but these types were actually interfaces with custom implementations.
For example, the type I wanted to map from looked something like this:
public class OriginalParent
{
public OriginalChild ChildProperty { get; }
}
public class OriginalChild
{
public string Value { get; }
}
And the type I wanted to map to looked something like this:
public interface INewParent
{
INewChild ChildProperty { get; }
}
public class NewParent : INewParent
{
public INewChild ChildProperty { get; }
}
public interface INewChild
{
string Value { get; }
}
public class NewChild : INewChild
{
public string Value { get; }
}
There were a few problems in doing this, mainly related to how I was using AutoMapper, but also relating to the setup of my new class. I needed to provide a set accessor to the members on my new classes and also provide a ChildProperty with a concrete type, rather than an interface.
AutoMapper needs a property accessor in order to set values, even if its private. As such, I had to change all my property accessors to look like this:
public string Value { get; private set; }
AutoMapper can map to an interface without throwing an exception, but it doesn't map the property values themselves, because it doesn't have a concrete type to instantiate. As such, I needed NewParent
to implement INewParent
whilst still providing a concrete type for the ChildProperty
property. This is achieved by providing an explicit interface implementation for INewChild
:
INewChild INewParent.ChildProperty { get { return ChildProperty; } }
public NewChild ChildProperty { get; private set; }
After I had made these changes, my AutoMapper configuration looked like this:
MapperConfiguration mapperConfiguratin = new MapperConfiguration(c =>
{
c.CreateMap<OldParent, NewParent>();
c.CreateMap<OldChild, NewChild>();
});
OldParent oldParent = new OldParent();
NewParent newParent = mapperConfiguration.CreateMapper().Map<NewParent>(oldParent);