ForAllMembers переопределяет уже определенные правила игнорирования

#c# #automapper

#c# #automapper

Вопрос:

Я использую AutoMapper , и мне нужно игнорировать элементы, где an Attribute не определен. Затем, если элемент не игнорируется, мне нужно сопоставить только те места, где определены значения. Мне удалось достичь этих двух по отдельности, но ForAllMembers / ForAllOtherMembers , похоже, переопределяет первое правило.

Допустим, у меня есть этот класс:

 public class Foo
{
    [MyCustomAttribute]
    public string Name { get; set; }

    public string IgnoreMe { get; set; }

    [MyCustomAttribute]
    public int? DontIgnoreNumber { get; set; }
}
  

Я хочу игнорировать IgnoreMe независимо. Затем, для Name и DontIgnoreNumber , я хочу сопоставить их, только если у них есть значение. Как я могу этого добиться?

Я пробовал это:

 Mapper.Initialize(cfg =>
{
    cfg.CreateMap<Foo, Foo>()
        .IgnoreAllNonAttributedEntities()
        .ForAllOtherMembers(opts =>
        {
            opts.Condition((src, dest, srcMember) =>
            {
                // Check if source is a default value
                return srcMember != null;
            });
        });
});
  

Я проверил, что ForAllOtherMembers правило работает. И я, отдельно, проверил, что IgnoreAllNonAttributedEntities работает. Когда я пытаюсь их объединить, ForAllOtherMembers кажется, что они имеют приоритет.

IgnoreAllNonAttributedEntities определяется как:

 public static IMappingExpression<TSource, TDestination> IgnoreAllNonAttributedEntities<TSource, TDestination>
    (this IMappingExpression<TSource, TDestination> expression)
{
    var flags = BindingFlags.Public | BindingFlags.Instance;
    //var sourceType = typeof(TSource);
    var destinationType = typeof(TDestination);

    foreach(var prop in destinationType.GetProperties(flags))
    {
        var attr = ReflectionHelpers.GetAttribute<MyCustomAttribute>(prop);
        if (attr == null)
        {
            expression.ForMember(prop.Name, opt => opt.Ignore());
        }
    }

    return expression;
}
  

Комментарии:

1. «Я хочу сопоставить их, только если у них есть значение»., если у этих свойств нет значения, он просто установит значение null или есть какой-либо другой сценарий, в котором это может быть проблемой?

2. Если это null или default , я не хочу сопоставлять, иначе сделайте сопоставление, если оно MyCustomAttribute определено. Таким образом, условие для сопоставления == имеет атрибут И не является нулевым значением.

3. Я в замешательстве… сопоставляются Foo ли они с самим собой? И если DontIgnoreNumber равно Null, каким должно быть значение в результирующем объекте? Не забывайте, что AutoMapper инициализирует результирующий объект, поэтому это важно.

4. @HoomanBahreini Да. У меня есть экземпляр Foo и другой экземпляр Foo . Оба уже инициализированы. Foo -> Foo. Если источник DontIgnoreNumbner есть null , то результат DontIgnoreNumber также должен быть null .

5. Тогда почему вы хотите это игнорировать? Разве вы не можете просто позволить Automapper скопировать источник в пункт назначения? Я не проверял это, но я считаю, что если source равно null, то назначение тоже будет null (не думаю, что вам нужно что-либо игнорировать).

Ответ №1:

Я только что запустил ваш код, и он работает так, как ожидалось. Однако, возможно, вас беспокоит значение по умолчанию для типов значений в c # (потому что вы проверяете только нули). Вот мое исправление для типов значений:

 Mapper.Initialize(cfg =>
{
    cfg.CreateMap<Foo, Foo>()
        .IgnoreAllNonAttributedEntities()
        .ForAllOtherMembers(opts =>
        {
            opts.Condition((src, dest, srcMember) =>
            {
                var srcType = srcMember?.GetType();
                if (srcType is null)
                {
                    return false;
                }

                return (srcType.IsClass amp;amp; srcMember != null)
                || (srcType.IsValueType
                amp;amp; !srcMember.Equals(Activator.CreateInstance(srcType)));
            });
        });
});
  

Я воссоздал ваш сценарий, используя последнюю версию automapper, доступную в NuGet (8.0.0.0).