使用 AutoMapper 从接口映射到具体类型

Use AutoMapper to map from an interface to a concrete type

我创建了 a dotNetFiddle that demonstrates the question here


这是我正在尝试做的事情的简化示例...假设我有以下接口:

public interface IPerson
{   
    int Id { get; set; }     
}

public interface IModelPerson : IPerson
{
    int BeautyCompetitionsWon { get; set; }
}

在实际实现中,有很多不同类型的人(例如IUglyPerson等)。这些是实体类型的合同,例如如下:

public class PersonEntity : IPerson
{
    public int Id { get; set; }
}

public class ModelPersonEntity : PersonEntity, IModelPerson
{
    public int BeautyCompetitionsWon { get; set; }
}

注意:我们也可能对每个合约类型有多个实现——例如IModelPerson 也可以由 SupermodelEntity 实现。

我们想将我们的实体类型映射到 DTO,它看起来像这样:

public abstract class PersonDto : IPerson
{
    public int Id { get; set; }
    public abstract string PersonType { get; }
}

public class ModelPersonDto : PersonDto, IModelPerson
{
    public int BeautyCompetitionsWon { get; set; }
    public override string PersonType
    {
        get { return "Model"; }
    }
}

因此,我们创建一个映射:

Mapper.Initialize(config =>
{
    config.CreateMap<IPerson, PersonDto>()
        .Include<IModelPerson, ModelPersonDto>()
        .ConstructUsing((IPerson person) => 
        {
            if (person is IModelPerson) return new ModelPersonDto();

            throw new InvalidOperationException("Unknown person type: " + person.GetType().FullName);
        })
        ;

    config.CreateMap<IModelPerson, ModelPersonDto>();
});

所以,我这里有两个问题。

1.有没有什么方法可以在没有 ConstructUsing 子句的情况下创建映射? 我认为 CreateMap 的更具体版本会为我们解决这个问题,但如果我不这样做没有 ConstructUsing 子句,AutoMapper 告诉我 "Instances of abstract classes cannot be created".

2。为什么我的子类的属性没有被映射? 如果我按如下方式执行映射:

var source = new ModelPersonEntity { Id = 100, BeautyCompetitionsWon = 9 };
var target = Mapper.Map<PersonDto>(source);

target.BeautyCompetitionsWon的预期值为 9,但实际值为 0。

问题 1:我不知道。

问题 2:当使用 .ConstructUsing() 时,请确保您 return 您所追求的映射对象而不是新实例。

例如

Mapper.Initialize(config =>
{
    config.CreateMap<IPerson, PersonDto>()
        .Include<IModelPerson, ModelPersonDto>()
        .ConstructUsing((IPerson person) => 
        {
            if (person is IModelPerson) return Mapper.Map<ModelPersonDto>(person);

            throw new InvalidOperationException("Unknown person type: " + person.GetType().FullName);
        })
        ;

    config.CreateMap<IModelPerson, ModelPersonDto>();
});