具有“Value”和“HasValue”的结构类型的通用自动映射器前提条件

Generic Automapper Precondition for Struct type with `Value`and `HasValue`

我正在使用 Automapper 和 Hot Chocolate。我在名为 Optional<> 的源 class 属性上使用结构类型,它具有方法 .Value.HasValue,用于确定客户端是否传入了这些值或不是。这用于从客户端到数据库的部分 update/patching。例如:

我的model/dto: public Optional<string> Name { get; init; }

在我的自动映射器配置文件中,我可以这样做:

.ForMember(dest => dest.Name, opt => {
    opt.PreCondition(src => src.Name.HasValue))
    opt.MapFrom(src => src.Name.Value)
})

这有效并且具有我想要的行为。但是,我不想最终为我的所有属性编写手动映射代码,这就是我首先使用 Automapper 的原因。

因此,我试图使此行为对类型 IOptional 的所有源类型属性通用。

我尝试了很多不同的东西。扩展方法和反射,以及使用类型转换器。

Automapper 自定义类型转换器将无法工作,因为您必须 return 一个值并且不能“退出”映射。

我已经尝试为 PreCondition 创建扩展方法,但我只能访问 AutoMapper 的 ResolverContext 对象,而且我还没有弄清楚如何利用它。例如:

.ForAllOtherMembers(o => o.PreCondition((src, dest, rc) => 
    // what do    
));

有没有人做过类似的事情?我想它与 Nullable<> 结构的概念相同,但我找不到任何适用于这种情况的实现。

认为我找到了令我满意的解决方案:

捕获所有可选源类型并应用解析器。

ForAllPropertyMaps(pm =>
        {
            return pm.SourceType != null && pm.SourceMember != null && pm.SourceType.IsGenericType &&
                   (pm.SourceType.GetGenericTypeDefinition() == typeof(Optional<>));
        }, (pm, c) =>
        {       
            c.MapFrom<AutoMapperExtensions.Resolver, IOptional>(pm.SourceMember.Name);
        });

基于 HasValue 解析:

public class Resolver : IMemberValueResolver<object, object, IOptional, object>
    {
        public object Resolve(object source, object destination, IOptional sourceMember, object destinationMember, ResolutionContext context)
        {
            return sourceMember.HasValue ? sourceMember.Value : destinationMember;
        }
    }

可以写得更漂亮,类型检查可能会有所不同,但这是一个起点。基于此评论:https://github.com/AutoMapper/AutoMapper/issues/2999#issuecomment-472692335