Automapper - 忽略IEnumerable<SelectListItem>的所有项

12

是否有办法让Automapper忽略某种类型的所有属性?我们正在尝试通过验证Automapper映射来提高代码质量,但是必须为所有手动创建的IEnumerable<SelectListItem>都添加一个 .Ignore() 在操作上比较繁琐,并且会减缓开发速度。

有什么想法吗?

创建映射后可能的想法:

    var existingMaps = Mapper.GetAllTypeMaps();
    foreach (var property in existingMaps)
    {
        foreach (var propertyInfo in property.DestinationType.GetProperties())
        {
            if (propertyInfo.PropertyType == typeof(List<SelectListItem>) || propertyInfo.PropertyType == typeof(IEnumerable<SelectListItem>))
            {
                property.FindOrCreatePropertyMapFor(new PropertyAccessor(propertyInfo)).Ignore();
            }
        }
    }
2个回答

18

Automapper目前不支持基于类型的属性忽略。

目前有三种方法可以忽略属性:

  • 在创建您的映射时使用Ignore()选项

  • Mapper.CreateMap<Source, Dest>()
        .ForMember(d => d.IgnoreMe, opt => opt.Ignore());
    

    这就是您想要避免的。

  • 使用IgnoreMapAttribute对您的IEnumerable<SelectListItem>属性进行注释。

  • 如果您的IEnumerable<SelectListItem>属性名称遵循某些命名约定,例如它们都以单词"Select"开头,您可以使用AddGlobalIgnore方法在全局范围内忽略它们:

  • Mapper.Initialize(c => c.AddGlobalIgnore("Select"));
    

    但是使用此方法只能匹配以某字符开头的内容。

然而,您可以为第一种选项创建一个方便的扩展方法,当调用CreateMap时,它会自动忽略给定类型的属性:

public static class MappingExpressionExtensions
{
    public static IMappingExpression<TSource, TDest> 
        IgnorePropertiesOfType<TSource, TDest>(
        this IMappingExpression<TSource, TDest> mappingExpression,
        Type typeToIgnore
        )
    {
        var destInfo = new TypeInfo(typeof(TDest));
        foreach (var destProperty in destInfo.GetPublicWriteAccessors()
            .OfType<PropertyInfo>()
            .Where(p => p.PropertyType == typeToIgnore))
        {
            mappingExpression = mappingExpression
                .ForMember(destProperty.Name, opt => opt.Ignore());
        }

        return mappingExpression;
    }
}

您可以按以下方式使用:

Mapper.CreateMap<Source, Dest>()
    .IgnorePropertiesOfType(typeof(IEnumerable<SelectListItem>));

所以它仍然不是一个全局解决方案,但您不必列出需要忽略哪些属性,它适用于同一类型的多个属性。

如果您不怕弄脏手:

目前有一种非常hacky的解决方案,它深入了 Automapper 的内部。我不知道这个API有多公开,因此该解决方案可能会在未来失效:

您可以订阅 ConfigurationStoreTypeMapCreated 事件。

((ConfigurationStore)Mapper.Configuration).TypeMapCreated += OnTypeMapCreated;

并在创建的TypeMap实例上直接添加基于类型的忽略:

private void OnTypeMapCreated(object sender, TypeMapCreatedEventArgs e)
{
    foreach (var propertyInfo in e.TypeMap.DestinationType.GetProperties())
    {
        if (propertyInfo.PropertyType == typeof (IEnumerable<SelectListItem>))
        {
            e.TypeMap.FindOrCreatePropertyMapFor(
                new PropertyAccessor(propertyInfo)).Ignore();
        }
    }
}

谢谢,是的,我已经找到了AddGlobalIgnore,但是想要在类型上进行操作。IgnorePropertiesOfType看起来不错,谢谢。只是很烦人,我们必须将其添加到数百个VM中。所以没有办法搜索所有映射模型,并通过反射查找类型为IEnumerable<SelectListItem>的属性,然后应用忽略属性吗? - GraemeMiller
为了动态添加属性,您需要像Postharp这样注入IL的东西。然而,我发现了一个相当肮脏/破解的全局解决方案。我会更新我的答案。 - nemesv
是的,我刚刚在查看源代码。我看到引入了GlobalIgnore,本来想为我们更改源代码,但这看起来应该能解决问题!谢谢 - GraemeMiller
如果你可以在一个中心位置和时间创建所有的映射,那么Mapper.GetAllTypeMaps可能是不错的选择。然而,如果你在不同的时间和地点添加映射,那么使用TypeMapCreated事件会更好。 - nemesv
@nemesv 我曾经使用 Mapper.Initialize(c => c.AddGlobalIgnore("Select")); 后,即使某些字段与 "Select" 字符串不匹配,所有的错误都消失了。这里有什么我忽略的吗? - Ram
显示剩余3条评论

1
如果您现在遇到这个问题,似乎有另一种解决方法。
Mapper.Initialize(cfg =>
{
    cfg.ShouldMapProperty = pi => pi.PropertyType != typeof(ICommand);
});

我没有研究这个是什么时候引入的。它似乎会阻止或允许你对其进行过滤。 请参阅:AutoMapper配置

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接