在我们当前的项目中,我们在类的静态构造函数中注册映射,这些类由多个线程调用。静态构造函数中的映射仅与该类相关。但仍然可以同时运行createmap的多个调用。此外,有时(主要是拷贝/过去的问题)相同的映射可以注册到不同类的静态构造函数中。
我试着用google搜索mapper.createmap是否是线程安全的。我只发现了以下几点:
在2012年的postIs Mapper.Map in AutoMapper thread-safe中,nemesv的答案中有一个注释,即createmap不是线程安全的,而且永远不会是线程安全的。
但我在github上发现了一个2014年的问题,在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中的值是相同的)。将map函数从两个线程更改有时会导致年龄值从负值变为正值(测试以不同年龄的高值结束)。但有时行为完全不同,年龄迭代停止值为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

07-24 21:45