AutoMapper: Map Interface to Abstract class - is t

2019-04-30 04:45发布

I'm using AutoMapper to map objects between different layers of my application. On the one side I have an interface which looks like this:

public interface MyRepo 
{
    IEnumerable<IRootObject> GetItems(param);
}

IRootObject looks like this:

public interface IRootObject
{
    int Id { get; set; }
    DateTime? Date { get; set; }
}

public interface IFirstSubObject : IRootObject 
{
    string MyFirstProp { get; set; }
}

public interface ISecondSubObject : IRootObject 
{
    string MySecondProp { get; set; }
}

So the GetItems()call actually returns an array of only IxxxSubObjectItems. On the other side the structure looks like this:

public abstract class MyCustomRoot
{
    protected MyCustomRoot(){}
    public int Id { get; set; }
    public DateTime? Date { get; set; }
}

public class MyCustomFirstSub : MyCustomRoot
{
    public MyCustomFirstSub() : base() {} 
    public string MyFirstProp { get; set; }
}

public class MyCustomSecondSub : MyCustomRoot
{
    public MyCustomSecondSub () : base() {} 
    public string MySecondProp { get; set; }
}

Now I've set up the mapper like so

AutoMapper.Mapper.CreateMap<IRootObject, MyCustomRoot>
    .Include<IFirstSubObject, MyCustomFirstSub>
    .Include<ISecondSubObject, MyCustomSecondSub>();

AutoMapper.Mapper.CreateMap<IFirstSubObject, MyCustomFirstSub>();
AutoMapper.Mapper.CreateMap<ISecondSubObject, MyCustomSecondSub>();

But I keep getting MapperExceptions ("Cannot construct abstract class", which makes sense in a way). I also call AssertConfigurationIsValid, and that passes for this code.
If I don't make the MyCustomRoot class abstract, then the mapping works, but I get a list of MyCustomRoot objects, while I actually would like to have a list of MyCustomxxxSub, because there is a Factory later on which uses this type to generate the correct UI...

I hope someone can point me in the right direction for this one!
Thanks!

2条回答
神经病院院长
2楼-- · 2019-04-30 05:26

Ok I found a way to actually do this! So with the Interfaces and Classes provided above, you can do something like this
(Remember: the MyCustomRoot class is abstract)

AutoMapper.Mapper.CreateMap<IRootObject, MyCustomRoot>
    .Include<IFirstSubObject, MyCustomFirstSub>
    .Include<ISecondSubObject, MyCustomSecondSub>();

and then use the followig Map call to map the objects:

public List<MyCustomRoot> PerformMapping(List<IRootObject> rootObjects)
{
    var returnList = new List<CustomRoot>();
    foreach(var rootObject in rootObjects)
    {
        var abstractObject = (MyCustomRoot)Mapper.Map(rootObject, rootObject.GetType(), typeof(MyCustomRoot));
        returnList.Add(abstractObject);
    }
    return returnList;
}

Now I actually get an array of MyCustomRoot objects, which are all the specific implementations.

This is exactly what I was looking for!

查看更多
男人必须洒脱
3楼-- · 2019-04-30 05:26

If so, then you want to map to that factory, inject it and let it create the correct instance in due time, since it's the factory that apparently knows what to instantiate.

查看更多
登录 后发表回答