Skip to content

Commit 4ff331c

Browse files
committed
Made EquivalentExpressions.AddCollectionMappers() thread-safe.
1 parent d21da88 commit 4ff331c

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

src/AutoMapper.Collection.Tests/AutoMapper.Collection.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
</ItemGroup>
6161
<ItemGroup>
6262
<Compile Include="MapCollectionWithEqualityTests.cs" />
63+
<Compile Include="MapCollectionWithEqualityThreadSafetyTests.cs" />
6364
<Compile Include="OptionsTests.cs" />
6465
<Compile Include="Properties\AssemblyInfo.cs" />
6566
</ItemGroup>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using AutoMapper.EquivalencyExpression;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Threading.Tasks;
5+
6+
namespace AutoMapper.Collection
7+
{
8+
public class MapCollectionWithEqualityThreadSafetyTests
9+
{
10+
public async Task Should_Work_When_Initialized_Concurrently()
11+
{
12+
Action act = () =>
13+
{
14+
new MapperConfiguration(cfg =>
15+
{
16+
cfg.AddCollectionMappers();
17+
});
18+
};
19+
var tasks = new List<Task>();
20+
for (var i = 0; i < 5; i++)
21+
{
22+
tasks.Add(Task.Run(act));
23+
}
24+
25+
await Task.WhenAll(tasks.ToArray());
26+
}
27+
}
28+
}

src/AutoMapper.Collection/EquivalencyExpression/EquivalentExpressions.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ namespace AutoMapper.EquivalencyExpression
1212
public static class EquivalentExpressions
1313
{
1414
private static readonly
15-
IDictionary<IConfigurationProvider, ConcurrentDictionary<TypePair, IEquivalentComparer>>
15+
ConcurrentDictionary<IConfigurationProvider, ConcurrentDictionary<TypePair, IEquivalentComparer>>
1616
EquivalentExpressionDictionary =
17-
new Dictionary<IConfigurationProvider, ConcurrentDictionary<TypePair, IEquivalentComparer>>();
17+
new ConcurrentDictionary<IConfigurationProvider, ConcurrentDictionary<TypePair, IEquivalentComparer>>();
1818

1919
private static ConcurrentDictionary<TypePair, IEquivalentComparer> _equalityComparisonCache = new ConcurrentDictionary<TypePair, IEquivalentComparer>();
2020

21-
private static readonly IDictionary<IConfigurationProvider, IList<IGeneratePropertyMaps>> GeneratePropertyMapsDictionary = new Dictionary<IConfigurationProvider, IList<IGeneratePropertyMaps>>();
21+
private static readonly ConcurrentDictionary<IConfigurationProvider, IList<IGeneratePropertyMaps>> GeneratePropertyMapsDictionary = new ConcurrentDictionary<IConfigurationProvider, IList<IGeneratePropertyMaps>>();
2222
private static IList<IGeneratePropertyMaps> _generatePropertyMapsCache = new List<IGeneratePropertyMaps>();
2323

2424
public static void AddCollectionMappers(this IMapperConfigurationExpression cfg)
@@ -41,10 +41,10 @@ private static void InsertBefore<TObjectMapper>(this IMapperConfigurationExpress
4141
foreach (var configurationObjectMapper in adds)
4242
configurationObjectMapper.ConfigurationProvider = c;
4343

44-
EquivalentExpressionDictionary.Add(c, _equalityComparisonCache);
44+
EquivalentExpressionDictionary.AddOrUpdate(c, _equalityComparisonCache, (type, old) => _equalityComparisonCache);
4545
_equalityComparisonCache = new ConcurrentDictionary<TypePair, IEquivalentComparer>();
4646

47-
GeneratePropertyMapsDictionary.Add(c, _generatePropertyMapsCache);
47+
GeneratePropertyMapsDictionary.AddOrUpdate(c, _generatePropertyMapsCache, (type, old) => _generatePropertyMapsCache);
4848
_generatePropertyMapsCache = new List<IGeneratePropertyMaps>();
4949
});
5050
}
@@ -54,7 +54,7 @@ internal static IEquivalentComparer GetEquivalentExpression(this IConfigurationO
5454
var typeMap = mapper.ConfigurationProvider.ResolveTypeMap(sourceType, destinationType);
5555
return typeMap == null ? null : GetEquivalentExpression(mapper.ConfigurationProvider, typeMap);
5656
}
57-
57+
5858
internal static IEquivalentComparer GetEquivalentExpression(IConfigurationProvider configurationProvider, TypeMap typeMap)
5959
{
6060
return EquivalentExpressionDictionary[configurationProvider].GetOrAdd(typeMap.Types,
@@ -70,8 +70,8 @@ internal static IEquivalentComparer GetEquivalentExpression(IConfigurationProvid
7070
/// <param name="mappingExpression">Base Mapping Expression</param>
7171
/// <param name="EquivalentExpression">Equivalent Expression between <typeparamref name="TSource"/> and <typeparamref name="TDestination"/></param>
7272
/// <returns></returns>
73-
public static IMappingExpression<TSource, TDestination> EqualityComparison<TSource, TDestination>(this IMappingExpression<TSource, TDestination> mappingExpression, Expression<Func<TSource, TDestination, bool>> EquivalentExpression)
74-
where TSource : class
73+
public static IMappingExpression<TSource, TDestination> EqualityComparison<TSource, TDestination>(this IMappingExpression<TSource, TDestination> mappingExpression, Expression<Func<TSource, TDestination, bool>> EquivalentExpression)
74+
where TSource : class
7575
where TDestination : class
7676
{
7777
var typePair = new TypePair(typeof(TSource), typeof(TDestination));
@@ -91,7 +91,7 @@ public static void SetGeneratePropertyMaps(this IMapperConfigurationExpression c
9191
{
9292
_generatePropertyMapsCache.Add(generatePropertyMaps);
9393
}
94-
94+
9595
private static IEquivalentComparer CreateEquivalentExpression(this IEnumerable<PropertyMap> propertyMaps)
9696
{
9797
if (!propertyMaps.Any() || propertyMaps.Any(pm => pm.DestinationProperty.GetMemberType() != pm.SourceMember.GetMemberType()))

0 commit comments

Comments
 (0)