Automapper转换系统对象列表

时间:2017-11-22 08:47:08

标签: c# automapper

我需要使用automapper将一个类转换为另一个类,我的对象如下所示:

public class Foo
{
    public List<object> Objects { get; set; }
}


public class Bar
{
    public List<object> Objects { get; set; }
}

public class FooItem
{
    public string Name { get; set; }
}

public class BarItem
{
    public string Name { get; set; }
}

项目可能有更多类型,不仅仅是FooItemBarItem,但为了简单起见,我只是使用这两种类型,我需要进行此设计。

我尝试过类似转换器之类的东西,但仍然没有运气。

这里是当前的基本转换代码

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<FooItem, BarItem>();
    cfg.CreateMap<Foo, Bar>();
});

var foo = new Foo()
{
    Objects = new List<object>() { new FooItem() { Name = "name" } }
};

var map = Mapper.Map<Foo, Bar>(foo);

目标是Bar对象在运行时包含BarItems列表,但到目前为止,我只是在运行时设法得到FooItem的列表。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

您是否只对BarItems列表感到满意?在这种情况下,您可以这样做:

var map = Mapper.Map<IEnumerable<FooItem>, List<BarItem>>(foo.Objects.Cast<FooItem>());

更新:您可以这样做。

class Program
{
    static void Main(string[] args)
    {
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<FooItem, BarItem>();
            cfg.CreateMap<Foo, Bar>()
            .ForMember(dest => dest.Objects, opt => opt.ResolveUsing<CustomResolver>());

        });
        Mapper.AssertConfigurationIsValid();
        var foo = new Foo()
        {
            Objects = new List<object>() { new FooItem() { Name = "name" } }
        };

        //var map = Mapper.Map<IEnumerable<FooItem>, List<BarItem>>(foo.Objects.Cast<FooItem>());
        var map = Mapper.Map<Foo, Bar>(foo);
    }
}

public class CustomResolver : IValueResolver<Foo, Bar, List<object>>
{ 
    public List<object> Resolve(Foo source, Bar destination, List<object> member, ResolutionContext context)
    {
        var map = Mapper.Map<IEnumerable<FooItem>, List<BarItem>>(source.Objects.Cast<FooItem>());
        return map.Cast<object>().ToList();
    }
}

答案 1 :(得分:2)

您可以在ConstructUsing子句中进行类型检查:

cfg.CreateMap<object, object>()
    .ConstructUsing(src => {
         if (src is FooItem) {
             return Mapper.Map<BarItem>(src);
         }
         // ...
         throw new InvalidOperationException($"Can not map source item of type '{src.GetType().FullName}'.");
     });

但您可能需要为Objects集合中的项目引入界面,因为地图对象 - &gt; object会覆盖所有其他地图,但我们想要使用地图FooItem - &gt; BarItem。

答案 2 :(得分:0)

受到@Ogglas的启发,我设法找到了一个有趣的解决方案,无需检查所有类型。

基本上我写了自己的ITypeConverter

public class CustomResolver : ITypeConverter<List<object>, List<object>>
{
    public List<object> Convert(List<object> source, List<object> destination, ResolutionContext context)
    {
        var objects = new List<object>();

        foreach (var obj in source)
        {
            var destinationType = context.ConfigurationProvider.GetAllTypeMaps().First(x => x.SourceType == obj.GetType()).DestinationType;
            var target = context.Mapper.Map(obj, obj.GetType(), destinationType);
            objects.Add(target);
        }

        return objects;
    }
}

从上下文中获取每种类型的正确映射。目前还不知道空值等等......

然后,配置automapper

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<FooItem, BarItem>();
    cfg.CreateMap<List<object>, List<object>>().ConvertUsing<CustomResolver>();
    cfg.CreateMap<Foo, Bar>(); 
});