使用开放式泛型进行自动映射并将源代码包含在 ForMember 语句中
Automapping using open generics and including the source in a ForMember statement
我最近从 Automapper 4.2.1 升级到 5.1.1,并且我遇到了以前有效的涉及开放泛型的映射问题。
以前,在自动映射器配置中,我有以下开放通用映射配置
CreateMap(typeof(IPager<>), typeof(ModelPager<>))
.ForMember("Items", e => e.MapFrom(o => (IEnumerable) o));
这在 Automapper 4 中有效,但在尝试通过 IMapper.Map<TDestination>(source)
映射时在 5 中失败并显示 InvalidOperaionException
。它似乎在执行 Items ForMember
操作的映射时失败,并出现异常消息“Sequence 不包含匹配元素”。 =26=]
如以下示例实现代码所示
IPager<TSource>
实现了 IEnumerable<TSource>
,而 ModelPager<TDestination>
的 Items
属性 是一个 IEnumerable<TDestination>
,因此转换应该是有效的。并且每个 TSource
到 TDestination
都存在一个有效映射
CreateMap<TSource, TDestination>();
IPager界面
public interface IPager<out TItem> : IEnumerable<TItem>
{
int CurrentPage { get; }
int PageCount { get; }
int PageSize { get; }
int TotalItems { get; }
}
IPager实现
public class Pager<TItem> : IPager<TItem>
{
private readonly IEnumerable<TItem> _items;
public Pager(IEnumerable<TItem> items,
int currentPage,
int pageSize,
int totalItems)
{
/// ... logic ...
this._items = items ?? Enumerable.Empty<TItem>();
this.CurrentPage = currentPage;
this.PageSize = pageSize;
this.TotalItems = totalItems;
}
public int CurrentPage { get; }
public int PageCount => (this.TotalItems + this.PageSize - 1) / this.PageSize;
public int PageSize { get; }
public int TotalItems { get; }
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
public IEnumerator<TItem> GetEnumerator() => this._items.GetEnumerator();
}
ModelPager
public class ModelPager<TItem>
{
public int CurrentPage { get; set; }
public IEnumerable<TItem> Items { get; set; }
public int PageCount { get; set; }
public int PageSize { get; set; }
public int TotalItems { get; set; }
}
在 Automapper 5 中映射它的正确方法是什么而不放弃 open generics by explicitly mapping each possible mapping, or by using a custom open generic type converter 这需要我手动映射所有属性并使用反射来解析分配的开放类型?
鉴于这看起来是一个错误 (AutoMapper #1624),可以使用 不需要的自定义开放通用 TypeConverter
来解决这个问题反射。
应将映射更改为与
类似的内容
CreateMap(typeof(IPager<>), typeof(ModelPager<>))
.ConvertUsing(typeof(PagerToModelPagerConverter<,>));
自定义 ITypeConverter
public class PagerToModelPagerConverter<TSource, TDestination> : ITypeConverter<IPager<TSource>, ModelPager<TDestination>>
{
public ModelPager<TDestination> Convert(IPager<TSource> source,
ModelPager<TDestination> destination,
ResolutionContext context)
{
var list = source.ToList(); // avoid redundant iterations
var itemMapping = context.Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>(list);
var modelPager = new ModelPager<TDestination>
{
CurrentPage = source.CurrentPage,
Items = itemMapping,
PageCount = source.PageCount,
PageSize = source.PageSize,
TotalItems = source.TotalItems
};
return modelPager;
}
我最近从 Automapper 4.2.1 升级到 5.1.1,并且我遇到了以前有效的涉及开放泛型的映射问题。
以前,在自动映射器配置中,我有以下开放通用映射配置
CreateMap(typeof(IPager<>), typeof(ModelPager<>))
.ForMember("Items", e => e.MapFrom(o => (IEnumerable) o));
这在 Automapper 4 中有效,但在尝试通过 IMapper.Map<TDestination>(source)
映射时在 5 中失败并显示 InvalidOperaionException
。它似乎在执行 Items ForMember
操作的映射时失败,并出现异常消息“Sequence 不包含匹配元素”。 =26=]
如以下示例实现代码所示
IPager<TSource>
实现了 IEnumerable<TSource>
,而 ModelPager<TDestination>
的 Items
属性 是一个 IEnumerable<TDestination>
,因此转换应该是有效的。并且每个 TSource
到 TDestination
CreateMap<TSource, TDestination>();
IPager界面
public interface IPager<out TItem> : IEnumerable<TItem>
{
int CurrentPage { get; }
int PageCount { get; }
int PageSize { get; }
int TotalItems { get; }
}
IPager实现
public class Pager<TItem> : IPager<TItem>
{
private readonly IEnumerable<TItem> _items;
public Pager(IEnumerable<TItem> items,
int currentPage,
int pageSize,
int totalItems)
{
/// ... logic ...
this._items = items ?? Enumerable.Empty<TItem>();
this.CurrentPage = currentPage;
this.PageSize = pageSize;
this.TotalItems = totalItems;
}
public int CurrentPage { get; }
public int PageCount => (this.TotalItems + this.PageSize - 1) / this.PageSize;
public int PageSize { get; }
public int TotalItems { get; }
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
public IEnumerator<TItem> GetEnumerator() => this._items.GetEnumerator();
}
ModelPager
public class ModelPager<TItem>
{
public int CurrentPage { get; set; }
public IEnumerable<TItem> Items { get; set; }
public int PageCount { get; set; }
public int PageSize { get; set; }
public int TotalItems { get; set; }
}
在 Automapper 5 中映射它的正确方法是什么而不放弃 open generics by explicitly mapping each possible mapping, or by using a custom open generic type converter 这需要我手动映射所有属性并使用反射来解析分配的开放类型?
鉴于这看起来是一个错误 (AutoMapper #1624),可以使用 不需要的自定义开放通用 TypeConverter
来解决这个问题反射。
应将映射更改为与
类似的内容CreateMap(typeof(IPager<>), typeof(ModelPager<>))
.ConvertUsing(typeof(PagerToModelPagerConverter<,>));
自定义 ITypeConverter
public class PagerToModelPagerConverter<TSource, TDestination> : ITypeConverter<IPager<TSource>, ModelPager<TDestination>>
{
public ModelPager<TDestination> Convert(IPager<TSource> source,
ModelPager<TDestination> destination,
ResolutionContext context)
{
var list = source.ToList(); // avoid redundant iterations
var itemMapping = context.Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>(list);
var modelPager = new ModelPager<TDestination>
{
CurrentPage = source.CurrentPage,
Items = itemMapping,
PageCount = source.PageCount,
PageSize = source.PageSize,
TotalItems = source.TotalItems
};
return modelPager;
}