c# – Automapper Mapper.CreateMap线程安全吗?

在我们当前的项目中,我们在类的静态构造函数中注册映射,这些构造函数由多个线程调用.静态构造函数中的映射仅与该类相关.但是仍然可以同时运行多个CreateMap调用.此外,偶尔(主要是复制/过去的问题)相同的映射可以在不同类的静态构造函数中注册.

我试图谷歌是否Mapper.CreateMap是线程安全的.我发现只有以下内容:

在2012年的Is Mapper.Map in AutoMapper thread-safe之后,在nemesv的回答中注意到CreateMap不是线程安全的,它永远不会.

但是我在2014年的GitHub Static DynamicMap and CreateMap APIs should be thread-safe上发现了一个问题,在3.2版本中被标记为关闭.这表明CreateMap现在应该是线程安全的.

你能确认CreateMap是线程安全的吗?我进行了一些测试,它看起来应该是,但如果有更深入了解的人可以确认这些信息就可以了.

编辑
经过一些额外的测试后,似乎CreateMap行为非常有趣:

我使用以下代码进行测试

    public void Test()
    {
        var items = new List<EntityA>();
        for (int i = 0; i < 100000; i++)
        {
            items.Add(new EntityA { FirstName = "A" + i });
        }

        ManualResetEvent stopChangingMappingFunction = new ManualResetEvent(false);

        Thread t1 = new Thread(() =>
        {

            int i = 1;
            while (true)
            {
                if (stopChangingMappingFunction.WaitOne(TimeSpan.Zero))
                    return;

                var i1 = i++;
                Mapper.CreateMap<EntityA, EntityB>().ForMember(x => x.Age, y => y.ResolveUsing(new Func<EntityA, object>(a => i1)));
            }
        });

        Thread t2 = new Thread(() =>
        {
            int i = -1;
            while (true)
            {
                if (stopChangingMappingFunction.WaitOne(TimeSpan.Zero))
                    return;

                var i1 = i--;
                Mapper.CreateMap<EntityA, EntityB>().ForMember(x => x.Age, y => y.ResolveUsing(new Func<EntityA, object>(a => i1)));
            }
        });

        List<int> distinctAges1 = null;
        List<int> distinctAges2 = null;

        Thread t3 = new Thread(() =>
        {
            Thread.Sleep(1000);

            var res = Mapper.Map<IList<EntityA>, IList<EntityB>>(items);
            distinctAges1 = res.Select(x => x.Age).Distinct().ToList();

            Thread.Sleep(1000);

            var res2 = Mapper.Map<IList<EntityA>, IList<EntityB>>(items);
            distinctAges2 = res.Select(x => x.Age).Distinct().ToList();

            stopChangingMappingFunction.Set();
        });

        t1.Start();
        t2.Start();
        t3.Start();

        t1.Join();
        t2.Join();
        t3.Join();

        Console.WriteLine("First Mapping: " + string.Join(", ", distinctAges1.ToArray()));
        Console.WriteLine("Second Mapping: " + string.Join(", ", distinctAges2.ToArray()));
        Console.ReadKey();
    }

public class EntityA
{
    public string FirstName { get; set; }
}

public class EntityB
{
    public string FirstName { get; set; }
    public int Age { get; set; }
}

在我调用第一个Map方法的所有测试中,这意味着CreateMap被冻结,并且不能再对映射函数进行更改(distinctAges1始终是一个唯一值,而且相同的值在distinctAges2中).从两个线程更改地图功能有时会导致Age从负数到正数的交替值增加(测试以不同年龄的高值结束).但有时行为完全不同,年龄迭代停止在1或-1的值.如果这个映射函数从更多线程更改,似乎有一些内部机制冻结映射函数的更改.但这种情况并非在100%的情况下发生

最佳答案
CreateMap是线程安全的.这并不意味着你的代码调用CreateMap.每个AppDomain只应调用一次CreateMap,通常的方法是这样的:https://github.com/jbogard/ContosoUniversity/blob/master/src/ContosoUniversity/Infrastructure/Mapping/AutoMapperBootstrapper.cs

地图不应使用通过闭包传递的任何上下文数据.你上面的代码是开始的坏地图,你应该重构它们以使用内置的上下文数据方法https://stackoverflow.com/a/31754133/58508

转载注明原文:c# – Automapper Mapper.CreateMap线程安全吗? - 代码日志