使用 AutoMapper 将成员数组转置为具有相应单数成员的对象集合
Transpose member arrays into collection of objects with corresponding singular members using AutoMapper
我有以下 类:
class Foo
{
public int X[];
public int Y[];
public int Z[];
}
class Bar
{
public int X;
public int Y;
public int Z;
}
我希望创建以下 AutoMapper 地图:
CreateMap<Foo, IEnumerable<Bar>>
这是将单个 Foo
对象映射到 Bar
的集合,这样 Foo.X[i]
和 Foo.Y[i]
将映射到 Bar[i].X
和 Bar[i].Y
。数组将始终具有相同的长度。使用内置功能的 AutoMapper 可以做到这一点吗?理想情况下,我想避免必须以编程方式显式映射每个成员。
作为额外的奖励,我还想使用 RecognizePostfixes("Postfix")
和以下版本的 Foo
支持源上的后缀:
class Foo
{
public int XPostfix[];
public int YPostfix[];
public int ZPostfix[];
}
在另一个问题上 from @LucianBargaoanu together with this answer,我能够使用 ITypeConverter
和 IEnumerable
扩展方法想出一个解决方案。
这是ITypeConverter
:
class TransposeConverter<TSource, TDestination> : ITypeConverter<TSource, IEnumerable<TDestination>> where TDestination : class, new()
{
public IEnumerable<TDestination> Convert(TSource source, IEnumerable<TDestination> destination, ResolutionContext context)
{
// Zip all the member collections from the source object together into a single collection then map to the destination based on the property names.
return typeof(TSource).GetProperties()
.Select(p => ((IEnumerable)p.GetValue(source)).Cast<object>().Select(item => (item, p.Name)))
.Zip(s => context.Mapper.Map<TDestination>(s.ToDictionary(k => k.Name, e => e.item)));
}
}
这是Zip
扩展方法:
public static IEnumerable<TResult> Zip<T, TResult>(this IEnumerable<IEnumerable<T>> collections, Func<IEnumerable<T>, TResult> resultSelector)
{
var enumerators = collections.Select(s => s.GetEnumerator()).ToArray();
while (enumerators.All(e => e.MoveNext()))
{
yield return resultSelector(enumerators.Select(e => e.Current));
}
}
但是,这只解决了问题的第一部分。它没有解决我希望处理 属性 名称后缀的 "added bonus" 部分。我为此筹集了another question。
我有以下 类:
class Foo
{
public int X[];
public int Y[];
public int Z[];
}
class Bar
{
public int X;
public int Y;
public int Z;
}
我希望创建以下 AutoMapper 地图:
CreateMap<Foo, IEnumerable<Bar>>
这是将单个 Foo
对象映射到 Bar
的集合,这样 Foo.X[i]
和 Foo.Y[i]
将映射到 Bar[i].X
和 Bar[i].Y
。数组将始终具有相同的长度。使用内置功能的 AutoMapper 可以做到这一点吗?理想情况下,我想避免必须以编程方式显式映射每个成员。
作为额外的奖励,我还想使用 RecognizePostfixes("Postfix")
和以下版本的 Foo
支持源上的后缀:
class Foo
{
public int XPostfix[];
public int YPostfix[];
public int ZPostfix[];
}
在另一个问题上 ITypeConverter
和 IEnumerable
扩展方法想出一个解决方案。
这是ITypeConverter
:
class TransposeConverter<TSource, TDestination> : ITypeConverter<TSource, IEnumerable<TDestination>> where TDestination : class, new()
{
public IEnumerable<TDestination> Convert(TSource source, IEnumerable<TDestination> destination, ResolutionContext context)
{
// Zip all the member collections from the source object together into a single collection then map to the destination based on the property names.
return typeof(TSource).GetProperties()
.Select(p => ((IEnumerable)p.GetValue(source)).Cast<object>().Select(item => (item, p.Name)))
.Zip(s => context.Mapper.Map<TDestination>(s.ToDictionary(k => k.Name, e => e.item)));
}
}
这是Zip
扩展方法:
public static IEnumerable<TResult> Zip<T, TResult>(this IEnumerable<IEnumerable<T>> collections, Func<IEnumerable<T>, TResult> resultSelector)
{
var enumerators = collections.Select(s => s.GetEnumerator()).ToArray();
while (enumerators.All(e => e.MoveNext()))
{
yield return resultSelector(enumerators.Select(e => e.Current));
}
}
但是,这只解决了问题的第一部分。它没有解决我希望处理 属性 名称后缀的 "added bonus" 部分。我为此筹集了another question。