如何配置Automapper以自动忽略具有ReadOnly属性的属性?

语境:

假设我有以下“目的地”类:

public class Destination { public String WritableProperty { get; set; } public String ReadOnlyProperty { get; set; } } 

和一个“source”类,其中一个属性具有ReadOnly属性:

 public class Source { public String WritableProperty { get; set; } [ReadOnly(true)] public String ReadOnlyProperty { get; set; } } 

很明显,但要明确:我将以下列方式从Source类映射到Destination类:

 Mapper.Map(source, destination); 

问题:

有哪些方法可以将Automapper配置为使用ReadOnly(true)属性自动忽略属性?

约束:

我使用Automapper的Profile类进行配置。 我不想弄脏具有Automapper特定属性的类。 我不想为每个只读属性配置Automapper,并且通过这种方式导致大量重复。

可能的(但不适合)解决方案:

1)将属性IgnoreMap添加到属性:

  [ReadOnly(true)] [IgnoreMap] public String ReadOnlyProperty { get; set; } 

我不想使用特定于自动化程序的属性来弄脏类并使其依赖于它。 另外,我不想在ReadOnly属性中添加其他属性。

2)配置Automapper忽略该属性:

 CreateMap() .ForSourceMember(src => src.ReadOnlyProperty, opt => opt.Ignore()) 

这不是一种方式,因为它迫使我为每个地方的每一处房产做这件事,也造成了很多重复。

扩展方法如下所示:

 public static class IgnoreReadOnlyExtensions { public static IMappingExpression IgnoreReadOnly( this IMappingExpression expression) { var sourceType = typeof(TSource); foreach (var property in sourceType.GetProperties()) { PropertyDescriptor descriptor = TypeDescriptor.GetProperties(sourceType)[property.Name]; ReadOnlyAttribute attribute = (ReadOnlyAttribute) descriptor.Attributes[typeof(ReadOnlyAttribute)]; if(attribute.IsReadOnly == true) expression.ForMember(property.Name, opt => opt.Ignore()); } return expression; } } 

要调用扩展方法:

Mapper.CreateMap().IgnoreReadOnly();

现在您还可以使用ForAllPropertyMaps全局禁用它:

 configure.ForAllPropertyMaps(map => map.SourceMember.GetCustomAttributes().OfType().Any(x => x.IsReadOnly), (map, configuration) => { configuration.Ignore(); }); 

如果你只想映射具有特定属性的属性,在我的情况下是[DataMember]属性,我根据上面的优秀回复编写了一个方法来处理源和目标:

 public static class ClaimMappingExtensions { public static IMappingExpression IgnoreAllButMembersWithDataMemberAttribute( this IMappingExpression expression) { var sourceType = typeof(TSource); var destinationType = typeof(TDestination); foreach (var property in sourceType.GetProperties()) { var descriptor = TypeDescriptor.GetProperties(sourceType)[property.Name]; var hasDataMemberAttribute = descriptor.Attributes.OfType().Any(); if (!hasDataMemberAttribute) expression.ForSourceMember(property.Name, opt => opt.Ignore()); } foreach (var property in destinationType.GetProperties()) { var descriptor = TypeDescriptor.GetProperties(destinationType)[property.Name]; var hasDataMemberAttribute = descriptor.Attributes.OfType().Any(); if (!hasDataMemberAttribute) expression.ForMember(property.Name, opt => opt.Ignore()); } return expression; } } 

它将被调用为另一种方法:

 Mapper.CreateMap().IgnoreAllButMembersWithDataMemberAttribute();