10

我相信 AutoMapper 在将对象列表从一种类型映射到另一种类型时使用缓存。看看下面的代码:

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Mapper.CreateMap<Source, Destination>()
                       .ForMember(dest => dest.SomeOtherNumber, opt => opt.Ignore());

            Mapper.AssertConfigurationIsValid();

            var sourceList = new List<Source>();

            var s1 = new Source {SomeNumber = 10};
            var s2 = new Source {SomeNumber = 69};

            sourceList.Add(s1);
            sourceList.Add(s1);
            sourceList.Add(s1);
            sourceList.Add(s2);

            var destList = Mapper.Map<List<Source>, List<Destination>>(sourceList);

            destList[0].SomeOtherNumber = 100;

            destList.ForEach(x => Console.WriteLine("SomeNumber: {0}, SomeOtherNumber: {1}", x.SomeNumber, x.SomeOtherNumber));
            Console.ReadLine();
        }
    }


    public class Source
    {
        public int SomeNumber { get; set; }
    }

    public class Destination
    {
        public int SomeNumber { get; set; }
        public int SomeOtherNumber { get; set; }
    }

}

代码的输出表明,即使我只设置了 destList 列表中第一个对象的 SomeOtherNumber,前三个项目也具有相同的属性值,因为它们引用了相同的对象引用。我想知道我是否可以禁用此行为,因此即使我在源列表中有重复的引用,我也不会在目标列表中有重复的引用。这有意义吗?

这是输出:

SomeNumber: 10, SomeOtherNumber: 100
SomeNumber: 10, SomeOtherNumber: 100
SomeNumber: 10, SomeOtherNumber: 100
SomeNumber: 69, SomeOtherNumber: 0
4

1 回答 1

5

我想说这暂时不能用 AutoMapper 来完成。实例缓存内置相当深,目前不能轻易关闭。尽管您的用例很奇怪......在列表中多次使用相同的源对象但您仍然想要不同的目标对象在我看来是非常不寻常的。

但它可以通过一个非常糟糕的 hack 来解决,因为它将全局关闭实例缓存并依赖于 AutoMapper 的实现细节,因此请谨慎使用。如果您仍然想尝试一下,下面提到的解决方案不适用于 Automapper 2.2.0 ,因为该错误仅在开发分支中修复,因此您需要从源代码构建 AutoMapper 或等待下一个版本。

但是这里有细节

实例缓存由TypeMapObjectMapperRegistry.CacheMappingStrategy [source]处理,与所有其他ITypeMapObjectMapper实现一样,它是一个私有类。

然而TypeMapObjectMapperRegistry.AllMappers,应该返回所有的字段是一个可以被覆盖ITypeMapObjectMapper的公共:Func

因此,在第一次使用 Mapper 类之前添加此代码:

var baseMappers = TypeMapObjectMapperRegistry.AllMappers();
TypeMapObjectMapperRegistry.AllMappers = () => 
    baseMappers.Where(m => m.GetType().Name != "CacheMappingStrategy").ToArray();

Mapper.CreateMap<Source, Destination>();
于 2013-01-22T20:08:00.867 回答