diff --git a/src/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs b/src/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs index a2cb08a60d..f58c79e2ed 100644 --- a/src/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs +++ b/src/Castle.Core/Components.DictionaryAdapter/DictionaryAdapterFactory.cs @@ -16,14 +16,15 @@ namespace Castle.Components.DictionaryAdapter { using System; using System.Collections; + using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; + using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Threading; - using System.Diagnostics; using Castle.Components.DictionaryAdapter.Xml; using Castle.Core.Internal; @@ -34,8 +35,8 @@ namespace Castle.Components.DictionaryAdapter /// public class DictionaryAdapterFactory : IDictionaryAdapterFactory { - private readonly SynchronizedDictionary interfaceToMeta = - new SynchronizedDictionary(); + private readonly ConcurrentDictionary interfaceToMeta = + new ConcurrentDictionary(); #region IDictionaryAdapterFactory @@ -132,8 +133,8 @@ private DictionaryAdapterMeta InternalGetAdapterMeta(Type type, descriptor = other.CreateDescriptor(); } - var typeBuilder = CreateTypeBuilder(type); - return CreateAdapterMeta(type, typeBuilder, descriptor); + var typeBuilder = CreateTypeBuilder(t); + return CreateAdapterMeta(t, typeBuilder, descriptor); }); } diff --git a/src/Castle.Core/Core/Internal/SynchronizedDictionary.cs b/src/Castle.Core/Core/Internal/SynchronizedDictionary.cs deleted file mode 100644 index 4f354f3222..0000000000 --- a/src/Castle.Core/Core/Internal/SynchronizedDictionary.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2004-2021 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Core.Internal -{ - using System; - using System.Collections.Generic; - using System.Threading; - - internal sealed class SynchronizedDictionary : IDisposable - { - private Dictionary items; - private ReaderWriterLockSlim itemsLock; - - public SynchronizedDictionary() - { - items = new Dictionary(); - itemsLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); - } - - public void AddOrUpdateWithoutTakingLock(TKey key, TValue value) - { - items[key] = value; - } - - public void Dispose() - { - itemsLock.Dispose(); - } - - public TValue GetOrAdd(TKey key, Func valueFactory) - { - TValue value; - - itemsLock.EnterReadLock(); - try - { - if (items.TryGetValue(key, out value)) - { - return value; - } - } - finally - { - itemsLock.ExitReadLock(); - } - - itemsLock.EnterUpgradeableReadLock(); - try - { - if (items.TryGetValue(key, out value)) - { - return value; - } - else - { - value = valueFactory.Invoke(key); - - itemsLock.EnterWriteLock(); - try - { - items.Add(key, value); - return value; - } - finally - { - itemsLock.ExitWriteLock(); - } - } - } - finally - { - itemsLock.ExitUpgradeableReadLock(); - } - } - - public TValue GetOrAddWithoutTakingLock(TKey key, Func valueFactory) - { - TValue value; - - if (items.TryGetValue(key, out value)) - { - return value; - } - else - { - value = valueFactory.Invoke(key); - items.Add(key, value); - return value; - } - } - - public void ForEach(Action action) - { - itemsLock.EnterReadLock(); - try - { - foreach (var item in items) - { - action.Invoke(item.Key, item.Value); - } - } - finally - { - itemsLock.ExitReadLock(); - } - } - } -} diff --git a/src/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs index 191cfe1a86..8d3a92235f 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/ClassProxyTargetContributor.cs @@ -176,7 +176,7 @@ private Type GetDelegateType(MetaMethod method, ClassEmitter @class) GetCacheKeyTypes(method), null); - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + return scope.TypeCache.GetOrAdd(key, _ => new DelegateTypeGenerator(method, targetType) .Generate(@class, namingScope) .BuildType()); diff --git a/src/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs index d834373c3b..9972c660be 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/ClassProxyWithTargetTargetContributor.cs @@ -121,7 +121,7 @@ private Type GetDelegateType(MetaMethod method, ClassEmitter @class) GetCacheKeyTypes(method), null); - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + return scope.TypeCache.GetOrAdd(key, _ => new DelegateTypeGenerator(method, targetType) .Generate(@class, namingScope) .BuildType()); @@ -136,7 +136,7 @@ private Type GetInvocationType(MetaMethod method, ClassEmitter @class) // no locking required as we're already within a lock - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => BuildInvocationType(method, @class)); + return scope.TypeCache.GetOrAdd(key, _ => BuildInvocationType(method, @class)); } private MethodGenerator IndirectlyCalledMethodGenerator(MetaMethod method, ClassEmitter proxy, diff --git a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs index deb0cde955..76d7e0fd85 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyTargetContributor.cs @@ -88,7 +88,7 @@ private Type GetInvocationType(MetaMethod method, ClassEmitter @class) // no locking required as we're already within a lock - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + return scope.TypeCache.GetOrAdd(key, _ => new CompositionInvocationTypeGenerator(method.Method.DeclaringType, method, method.Method, diff --git a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs index d3eca51ad7..d4f146cad4 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/InterfaceProxyWithoutTargetContributor.cs @@ -95,7 +95,7 @@ private Type GetInvocationType(MetaMethod method, ClassEmitter emitter) // no locking required as we're already within a lock - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + return scope.TypeCache.GetOrAdd(key, _ => new CompositionInvocationTypeGenerator(methodInfo.DeclaringType, method, methodInfo, diff --git a/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs b/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs index 9f63b269bd..e0074a6ff7 100644 --- a/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs +++ b/src/Castle.Core/DynamicProxy/Contributors/MixinContributor.cs @@ -140,7 +140,7 @@ private Type GetInvocationType(MetaMethod method, ClassEmitter emitter) // no locking required as we're already within a lock - return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ => + return scope.TypeCache.GetOrAdd(key, _ => new CompositionInvocationTypeGenerator(method.Method.DeclaringType, method, method.Method, diff --git a/src/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs b/src/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs index e82c7c5e89..0fb157e8c6 100644 --- a/src/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs +++ b/src/Castle.Core/DynamicProxy/Internal/InvocationHelper.cs @@ -15,18 +15,16 @@ namespace Castle.DynamicProxy.Internal { using System; - using System.Collections.Generic; + using System.Collections.Concurrent; using System.Diagnostics; using System.Reflection; - using System.Threading; - using Castle.Core.Internal; using Castle.DynamicProxy.Generators; internal static class InvocationHelper { - private static readonly SynchronizedDictionary cache = - new SynchronizedDictionary(); + private static readonly ConcurrentDictionary cache = + new ConcurrentDictionary(); public static MethodInfo GetMethodOnObject(object target, MethodInfo proxiedMethod) { diff --git a/src/Castle.Core/DynamicProxy/ModuleScope.cs b/src/Castle.Core/DynamicProxy/ModuleScope.cs index 908b91a445..34471389fe 100644 --- a/src/Castle.Core/DynamicProxy/ModuleScope.cs +++ b/src/Castle.Core/DynamicProxy/ModuleScope.cs @@ -17,14 +17,13 @@ namespace Castle.DynamicProxy { using System; + using System.Collections.Concurrent; using System.Collections.Generic; - using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Resources; - using System.Threading; using Castle.Core.Internal; using Castle.DynamicProxy.Generators; @@ -54,7 +53,7 @@ public class ModuleScope private readonly string weakModulePath; // Keeps track of generated types - private readonly SynchronizedDictionary typeCache = new SynchronizedDictionary(); + private readonly ConcurrentDictionary typeCache = new ConcurrentDictionary(); // Used to lock the module builder creation private readonly object moduleLocker = new object(); @@ -148,7 +147,7 @@ internal INamingScope NamingScope get { return namingScope; } } - internal SynchronizedDictionary TypeCache => typeCache; + internal ConcurrentDictionary TypeCache => typeCache; /// /// Gets the key pair used to sign the strong-named assembly generated by this . @@ -504,15 +503,18 @@ private void AddCacheMappings(AssemblyBuilder builder) { var mappings = new Dictionary(); - typeCache.ForEach((key, value) => + foreach (var kvp in typeCache) { + var key = kvp.Key; + var value = kvp.Value; + // NOTE: using == returns invalid results. // we need to use Equals here for it to work properly if (builder.Equals(value.Assembly)) { mappings.Add(key, value.FullName); } - }); + }; CacheMappingsAttribute.ApplyTo(builder, mappings); } @@ -551,7 +553,7 @@ public void LoadAssemblyIntoCache(Assembly assembly) if (loadedType != null) { - typeCache.AddOrUpdateWithoutTakingLock(mapping.Key, loadedType); + typeCache[mapping.Key] = loadedType; } } } diff --git a/src/Castle.Core/DynamicProxy/ProxyUtil.cs b/src/Castle.Core/DynamicProxy/ProxyUtil.cs index 79bd611769..0dfe37e95e 100644 --- a/src/Castle.Core/DynamicProxy/ProxyUtil.cs +++ b/src/Castle.Core/DynamicProxy/ProxyUtil.cs @@ -17,12 +17,11 @@ namespace Castle.DynamicProxy { using System; - using System.Collections.Generic; + using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; - using System.Threading; using Castle.Core.Internal; using Castle.DynamicProxy.Generators; @@ -30,7 +29,7 @@ namespace Castle.DynamicProxy public static class ProxyUtil { - private static readonly SynchronizedDictionary internalsVisibleToDynamicProxy = new SynchronizedDictionary(); + private static readonly ConcurrentDictionary internalsVisibleToDynamicProxy = new ConcurrentDictionary(); /// /// Creates a delegate of the specified type to a suitable `Invoke` method