【问题标题】:Transpose member arrays into collection of objects with corresponding singular members using AutoMapper使用 AutoMapper 将成员数组转换为具有相应奇异成员的对象集合
【发布时间】:2020-03-08 15:28:53
【问题描述】:

我有以下课程:

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].XBar[i].Y。数组将始终具有相同的长度。使用内置功能的 AutoMapper 是否可以做到这一点?理想情况下,我希望避免以编程方式显式映射每个成员。

作为额外的奖励,我还希望使用RecognizePostfixes("Postfix") 和以下版本的Foo 支持源上的后缀:

class Foo
{
    public int XPostfix[];
    public int YPostfix[];
    public int ZPostfix[];
}

【问题讨论】:

  • 用LINQ写,如果有重复,加AM。
  • @LucianBargaoanu 您能否发布这将如何作为答案,因为如果不明确指定源成员数组,我无法看到如何使用 LINQ 实现它?我目前正在使用反射处理ITypeConverter 解决方案,但我觉得 AutoMapper 仍然应该是其中的一部分,特别是因为我刚刚添加的关于后缀的问题的最后一部分。我基本上想以任何必要的方式进行映射,同时仍然利用 ResolutionContext 中的任何 AutoMapper 配置。
  • Zip LINQ 运算符在这里提供帮助。
  • @LucianBargaoanu Zip 在我的情况下没有帮助,因为我的用例具有任意数量的属性。有一个复杂的答案here 使用ZipAggregate 以某种方式实现这一点,但它确实滥用Aggregate 并使用随机源成员数组来决定其初始种子大小。使用Zip 的自定义重载扩展方法的其他答案似乎更合适,我为此添加了answer。感谢您的帮助!

标签: c# arrays collections automapper transpose


【解决方案1】:

通过@LucianBargaoanu 的pointer in the right direction 和另一个问题的this answer,我能够提出使用ITypeConverterIEnumerable 扩展方法的解决方案。

这是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));
    }
}

但是,这只解决了问题的第一部分。它不能解决我希望处理属性名称后缀的“额外奖励”部分。我为此提出了another question

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多