当映射对象的某些属性具有相同的名称但具有不同的类型时,是否可以设置某种导致映射或验证过程失败的全局配置?
来源/目标类型
public class UserData1
{
public int Id { get; set; }
}
public class UserData2
{
public string Id { get; set; }
}
映射配置
Mapper.Initialize(cfg =>
{
cfg.CreateMap<UserData1, UserData2>();
});
预期的行为
当映射属性的类型不同时,AssertConfigurationIsValid或Map应触发某种验证异常。
实际行为
int属性无例外地映射到字符串。
复制步骤
// Passes OK
Mapper.Configuration.AssertConfigurationIsValid();
// Mapping is successful
var user2 = Mapper.Map<UserData2>(new UserData1 { Id = 156 });
答案 0 :(得分:0)
没有可用的内置解决方案,但是可以使用自定义配置来实现。
类似这样的东西:
Mapper.Initialize(cfg => {
cfg.CreateMap<UserData1, UserData2>();
...
cfg.ForAllMaps((typeMap, mappingExpr) =>
{
foreach (var map in typeMap.PropertyMaps) {
var sourcePropInfo = map.SourceMember as PropertyInfo;
var destPropInfo = map.DestinationMember as PropertyInfo;
if (sourcePropInfo == null || destPropInfo == null) continue;
if (sourcePropInfo.PropertyType != destPropInfo.PropertyType)
throw new Exception("Wrong property type!");
}
});
});
此旧帖子已作为参考使用,并已更新为可与新版本的automapper一起使用 https://stackoverflow.com/a/38080647/1703620
答案 1 :(得分:0)
利用Artyom的答案作为启发,我编写了一个单元测试,以将这些隐式类型转换限制在我们可以接受的几种情况下。
该方法是查找所有没有显式映射的属性映射,并过滤掉我们要允许的几种方案。
XUnit测试:
[Fact]
public void AllMappedPropertiesAreSameTypeOrAreMappedExplicitly()
{
ServiceCollection theCollection = new ServiceCollection();
theCollection.AddMssAutoMapper();
IMapper theMapper = BuildProductionMapper();
//Store all explicit mappings for easy lookup
System.Collections.Generic.HashSet<(Type SourceType, Type DestType)> theExplicitMappings =
theMapper.ConfigurationProvider.GetAllTypeMaps()
.Select( map => (map.SourceType, map.DestinationType) )
.ToHashSet();
var theIllegalMaps =
from typeMap in theMapper.ConfigurationProvider.GetAllTypeMaps()
from propMap in typeMap.PropertyMaps
let sourceType = propMap.SourceType
let destType = propMap.DestinationType
let bothTypes = new[] { sourceType, destType }
where sourceType != null && destType != null
where sourceType != destType
//Anything that's explicitly mapped is permitted
where !theExplicitMappings.Contains( (sourceType, destType) )
//enums to string and vice versa is permitted
where !( sourceType.IsEnum || sourceType == typeof( string ) && destType.IsEnum || destType == typeof( string ) )
//mapping from one collection to another is okay
where !bothTypes.All( type => type.IsAssignableTo( typeof( IEnumerable ) ) )
select new
{
SourceType = typeMap.SourceType,
DestinationType = typeMap.DestinationType,
SourceMemberName = propMap.SourceMember.Name,
DestMemberName = propMap.DestinationMember.Name,
SourceMemberType = sourceType,
DestinationMemberType = destType
};
var illegalMapsList = theIllegalMaps.ToList();
foreach( var illegalMap in illegalMapsList )
{
Console.Out.WriteLine( $"Found disallowed property mapping from '{illegalMap.SourceType}.{illegalMap.SourceMemberName}' to '{illegalMap.DestinationType}.{illegalMap.DestMemberName}'" );
Console.Out.WriteLine( $"Property name: {illegalMap.SourceMemberName}" );
Console.Out.WriteLine( $"implicit mapping from {illegalMap.SourceMemberType} to {illegalMap.DestinationMemberType} is not allowed." );
Console.Out.WriteLine( $"Please map these types explicitly." );
}
if( illegalMapsList.Any() )
{
throw new Exception( "One or more ambiguous mappings were found that need to be handled explicitly. See console output for details." );
}
}