如何使用 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
能够理解 SourceDataType
和 DestinationDataType
之间的映射,并将 SourceDataType
瞬间映射到 DestinationDataType
瞬间。但是,目标对象被赋予了 SourceDataType
值。
我也试过DynamicMap
,结果一样。
var destination = AutoMapper.Mapper.DynamicMap<Source, Destination>(source);
var destination = AutoMapper.Mapper.DynamicMap<Destination>(source);
有没有办法配置Automapper
动态映射内部类?
这里有两个问题:
首先,您没有定义 SourceDataType
和 DestinationDataType
之间的任何关系,因此 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);
}
我定义了下面四个类
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
能够理解 SourceDataType
和 DestinationDataType
之间的映射,并将 SourceDataType
瞬间映射到 DestinationDataType
瞬间。但是,目标对象被赋予了 SourceDataType
值。
我也试过DynamicMap
,结果一样。
var destination = AutoMapper.Mapper.DynamicMap<Source, Destination>(source);
var destination = AutoMapper.Mapper.DynamicMap<Destination>(source);
有没有办法配置Automapper
动态映射内部类?
这里有两个问题:
首先,您没有定义 SourceDataType
和 DestinationDataType
之间的任何关系,因此 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);
}