如何使用 AutoMapper 动态映射内部类型

How to dynamically map inner type using AutoMapper

我定义了下面四个类

   public class Source
    {
        public object Value { get; set; }
    }

    public class Destination
    {
        public object Value { get; set; }
    }

    public class SourceDataType
    {
        //...
    }

    public class DestinationDataType
    {
        //...
    }

我将 Automapper 配置如下:

        AutoMapper.Mapper.CreateMap<Source, Destination>();
        AutoMapper.Mapper.CreateMap<SourceDataType, DestinationDataType>();

然后在我的代码中,我创建了一个具有 SourceDateType 值的 Source 对象,并尝试将其映射到 Destination 对象。

        var source = new Source { Value = new SourceDataType() };

        var destination = AutoMapper.Mapper.Map<Source, Destination>(source);

        Console.WriteLine(destination.GetType());
        Console.WriteLine(destination.Value.GetType());

目标类型符合预期。我希望 Automapper 能够理解 SourceDataTypeDestinationDataType 之间的映射,并将 SourceDataType 瞬间映射到 DestinationDataType 瞬间。但是,目标对象被赋予了 SourceDataType 值。

我也试过DynamicMap,结果一样。

        var destination = AutoMapper.Mapper.DynamicMap<Source, Destination>(source);
        var destination = AutoMapper.Mapper.DynamicMap<Destination>(source);

有没有办法配置Automapper动态映射内部类?

这里有两个问题:

首先,您没有定义 SourceDataTypeDestinationDataType 之间的任何关系,因此 AutoMapper 无法知道如何转换这些类型。

其次,这两个属性的类型是object,并且(据我所知)AutoMapper不会根据动态类型进行转换。

您也许可以使用 Custom Type Converter 解决此问题;但是,由于 属性 属于 object.

类型,我对此持保留意见

总之,您可以尝试根据以下映射添加一些内容:

Mapper.CreateMap<object, object>().ConvertUsing(src =>
{
    if (src is SourceDataType)
        return new DestinationDataType(); // Put your conversion code here.
    else
        return src;
});

正如我所说,我不喜欢这样,因为 object 将匹配所有 属性 类型。

这是可以解决的,尽管如果越来越多的类型被添加到组合中,它将变得难以维护和复杂。无论如何,对于您的情况,这将起作用:

    [Test]
    public void CustomMapping()
    {
        //arrange
        Mapper.CreateMap<Source, Destination>()
            .ForMember(d=>d.Value, opt=>opt.ResolveUsing(ResolveValue));
        Mapper.CreateMap<SourceDataType, DestinationDataType>();

        var source = new Source { Value = new SourceDataType() };

        //act
        var destination = Mapper.Map<Source, Destination>(source);

        //assert
        destination.Value.Should().Be.OfType<DestinationDataType>();
    }

    private object ResolveValue(ResolutionResult result)
    {
        var source = result.Context.SourceValue as Source;

        if (result.Context.IsSourceValueNull || source == null || !(source.Value is SourceDataType))
        {
            return null;
        }
        var sourceValue = source.Value as SourceDataType;

        return result.Context.Engine.Map<DestinationDataType>(sourceValue);
    }