如何配置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
现在您还可以使用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();