使用 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>();
});
我创建了 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>();
});