我有一个这样的映射器:
CreateMap<Source, ICollection<Dest>>()
.ConvertUsing((src, dst, context) =>
{
return context.Mapper.Map<ICollection<Dest>>
(new SourceItem[] { src.Item1, src.Item2 ... }.Where(item => SomeFilter(item)),
opts => opts.Items["SomethingFromSource"] = src.Something);
});
CreateMap<SourceItem, Dest>()
.ForMember(d => d.Something, opts => opts.MapFrom((src, dst, dstItem, context)
=> (string)context.Items["SomethingFromSource"]));
这给了我一个例外,说
You must use a Map overload that takes Action<IMappingOperationOptions>
。好吧,我确实使用了执行此操作的 Map
重载。我还能怎么做?
这是因为这个变化:
https://github.com/AutoMapper/AutoMapper/pull/3150
您可以通过访问ResolutionContext的Options属性来获取项目。
将
context.Items["SomethingFromSource"]
更改为 context.Options.Items["SomethingFromSource"]
。
没有 Item 时,
ResolutionContext
与 DefaultContext
相同。因此 ResolutionContext.Items
属性将抛出异常。ResolutionContext.Items
就不会与DefaultContext
相同。因此 ResolutionContext.Items
将返回列表。
虽然
ResolutionContext.Options.Items
总是返回列表,但它不会抛出任何异常,无论它是否为空。我相信这就是错误消息的含义,因为 ResolutionContext.Options
是 IMappingOperationOptions
编辑于 2023 年 8 月 21 日:以上是在 AutoMapper 12 之前编写的。对于 12 及更高版本,请参阅下面的@Pieter Riesz 回答。感谢@Stoyan Dimov 和@Peter Riesz 的更新。
您可以通过访问ResolutionContext的
Options
属性来获取项目。
=> context.Options.Items["SomethingFromSource"]
在12.0.0版本中,
Options
已被删除,您需要升级。
如果您想检查
TryGetItems
调用中是否传递了上下文,可以使用 Map
。
=> context.TryGetItems(out var items) ? (string)items["SomethingFromSource"] : null
https://docs.automapper.org/en/latest/12.0-Upgrade-Guide.html
此扩展可以帮助迁移到 AutoMapper 12
public static class AutoMapperExtensions
{
public static TDestination MapOptions<TDestination>(this IMapper mapper, object source, Action<IMappingOperationOptions<object, TDestination>> OptionalOptions = null)
{
return mapper.Map(source, OptionalOptions ?? (_ => {}) );
}
}
在已注入 IMapper 的类中
public class Command
{
protected readonly IMapper AutoMapper;
public Command(IMapper mapper)
{
AutoMapper = mapper;
}
private SomethingToDo()
{
var list = new List<string>();
// change for 12
var result = AutoMapper.MapOptions<IList<Item>>(list);
// prior to 12
//var result = AutoMapper.Map<IList<Item>>(list);
}
}
使用内部映射器时的几个注意点(即
context.Mapper
)
首先,尽量不要使用
context.Mapper.Map<TDestination>(...)
,改用context.Mapper.Map<TSource, TDestination>(...)
,效果会好很多。
其次,在内部映射器中使用上下文会破坏封装。如果您需要设置内部对象中的值,请考虑以下两种解决方案:
如果您想在内部地图之后设置值
context.Mapper.Map<Source, Dest> (source, opts => opts.AfterMap((s, d) =>
d.Something = source.Something))
如果您想在内部地图之前设置值
context.Mapper.Map<Source, Dest> (source, new Dest()
{
Something = source.Something
})