Skip to content

Commit 690e637

Browse files
committed
allocate _runtimeTypeDetails lazily
1 parent 7eeaf59 commit 690e637

File tree

3 files changed

+15
-20
lines changed

3 files changed

+15
-20
lines changed

src/AutoMapper/ApiCompatBaseline.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ TypeCannotChangeClassification : Type 'AutoMapper.Execution.TypeMapPlanBuilder'
9393
MembersMustExist : Member 'public System.Linq.Expressions.LambdaExpression AutoMapper.Execution.TypeMapPlanBuilder.CreateMapperLambda(System.Collections.Generic.HashSet<AutoMapper.TypeMap>)' does not exist in the implementation but it does exist in the contract.
9494
MembersMustExist : Member 'public System.Linq.Expressions.ParameterExpression AutoMapper.Execution.TypeMapPlanBuilder.Source.get()' does not exist in the implementation but it does exist in the contract.
9595
MembersMustExist : Member 'public System.Collections.Generic.IEnumerator<TFeature> AutoMapper.Features.Features<TFeature>.GetEnumerator()' does not exist in the implementation but it does exist in the contract.
96+
TypesMustExist : Type 'AutoMapper.Internal.ConcurrentDictionaryWrapper<TKey, TValue>' does not exist in the implementation but it does exist in the contract.
9697
MembersMustExist : Member 'public System.Reflection.ConstructorInfo System.Reflection.ConstructorInfo AutoMapper.Internal.ConstructorParameters.Constructor' does not exist in the implementation but it does exist in the contract.
9798
MembersMustExist : Member 'public System.Reflection.ParameterInfo[] System.Reflection.ParameterInfo[] AutoMapper.Internal.ConstructorParameters.Parameters' does not exist in the implementation but it does exist in the contract.
9899
MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Internal.TypePair AutoMapper.Internal.MapRequest.RequestedTypes' does not exist in the implementation but it does exist in the contract.
@@ -119,4 +120,4 @@ MembersMustExist : Member 'public AutoMapper.Internal.TypePair AutoMapper.Intern
119120
MembersMustExist : Member 'public System.Linq.IQueryable<TDestination> AutoMapper.QueryableExtensions.Extensions.Map<TSource, TDestination>(System.Linq.IQueryable<TSource>, System.Linq.IQueryable<TDestination>, AutoMapper.IConfigurationProvider)' does not exist in the implementation but it does exist in the contract.
120121
MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyCollection<System.Reflection.MemberInfo> AutoMapper.QueryableExtensions.MemberVisitor.MemberPath.get()' does not exist in the implementation but it does exist in the contract.
121122
TypesMustExist : Type 'AutoMapper.QueryableExtensions.Impl.MemberAccessQueryMapperVisitor' does not exist in the implementation but it does exist in the contract.
122-
Total Issues: 120
123+
Total Issues: 121
Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
11
using System.Collections.Concurrent;
2-
32
namespace AutoMapper.Internal;
4-
53
public readonly struct LockingConcurrentDictionary<TKey, TValue>
64
{
7-
private readonly ConcurrentDictionaryWrapper<TKey, Lazy<TValue>> _dictionary;
8-
public LockingConcurrentDictionary(Func<TKey, TValue> valueFactory, int capacity = 31) =>
9-
_dictionary = new(key => new(() => valueFactory(key)), capacity);
10-
public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key).Value;
11-
}
12-
public readonly struct ConcurrentDictionaryWrapper<TKey, TValue>
13-
{
14-
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
15-
private readonly Func<TKey, TValue> _valueFactory;
16-
public ConcurrentDictionaryWrapper(Func<TKey, TValue> valueFactory, int capacity = 31)
5+
private readonly Func<TKey, Lazy<TValue>> _valueFactory;
6+
private readonly ConcurrentDictionary<TKey, Lazy<TValue>> _dictionary;
7+
public LockingConcurrentDictionary(Func<TKey, TValue> valueFactory, int capacity = 31)
178
{
9+
_valueFactory = key => new(()=>valueFactory(key));
1810
_dictionary = new(Environment.ProcessorCount, capacity);
19-
_valueFactory = valueFactory;
2011
}
21-
public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory);
12+
public TValue GetOrAdd(in TKey key) => _dictionary.GetOrAdd(key, _valueFactory).Value;
2213
}

src/AutoMapper/ProfileMap.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using AutoMapper.Configuration.Conventions;
2+
using System.Collections.Concurrent;
23
namespace AutoMapper;
34
[DebuggerDisplay("{Name}")]
45
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -8,7 +9,7 @@ public class ProfileMap
89
private TypeMapConfiguration[] _typeMapConfigs;
910
private Dictionary<TypePair, TypeMapConfiguration> _openTypeMapConfigs;
1011
private Dictionary<Type, TypeDetails> _typeDetails;
11-
private ConcurrentDictionaryWrapper<Type, TypeDetails> _runtimeTypeDetails;
12+
private ConcurrentDictionary<Type, TypeDetails> _runtimeTypeDetails;
1213
public ProfileMap(IProfileConfiguration profile, IGlobalConfigurationExpression configuration = null)
1314
{
1415
var globalProfile = (IProfileConfiguration)configuration;
@@ -74,7 +75,6 @@ internal void Clear()
7475
{
7576
_typeDetails = null;
7677
_typeMapConfigs = null;
77-
_runtimeTypeDetails = new(TypeDetailsFactory, 2 * _openTypeMapConfigs.Count);
7878
}
7979
public bool AllowNullCollections { get; }
8080
public bool AllowNullDestinationValues { get; }
@@ -99,17 +99,20 @@ public TypeDetails CreateTypeDetails(Type type)
9999
{
100100
if (_typeDetails == null)
101101
{
102-
return _runtimeTypeDetails.GetOrAdd(type);
102+
if (_runtimeTypeDetails == null)
103+
{
104+
Interlocked.CompareExchange(ref _runtimeTypeDetails, new(Environment.ProcessorCount, 2 * _openTypeMapConfigs.Count), null);
105+
}
106+
return _runtimeTypeDetails.GetOrAdd(type, (type, profile) => new(type, profile), this);
103107
}
104108
if (_typeDetails.TryGetValue(type, out var typeDetails))
105109
{
106110
return typeDetails;
107111
}
108-
typeDetails = TypeDetailsFactory(type);
112+
typeDetails = new(type, this);
109113
_typeDetails.Add(type, typeDetails);
110114
return typeDetails;
111115
}
112-
private TypeDetails TypeDetailsFactory(Type type) => new(type, this);
113116
public void Register(IGlobalConfiguration configuration)
114117
{
115118
foreach (var config in _typeMapConfigs)

0 commit comments

Comments
 (0)