diff --git a/LightweightIocContainer.Validation/LightweightIocContainer.Validation.xml b/LightweightIocContainer.Validation/LightweightIocContainer.Validation.xml index 5bedfa5..778835c 100644 --- a/LightweightIocContainer.Validation/LightweightIocContainer.Validation.xml +++ b/LightweightIocContainer.Validation/LightweightIocContainer.Validation.xml @@ -13,7 +13,6 @@ Validator for your to check if everything can be resolved with your current setup - The diff --git a/LightweightIocContainer/IocContainer.cs b/LightweightIocContainer/IocContainer.cs index 404b561..a3fa7de 100644 --- a/LightweightIocContainer/IocContainer.cs +++ b/LightweightIocContainer/IocContainer.cs @@ -2,6 +2,7 @@ // Created: 2019-05-20 // Copyright(c) 2019 SimonG. All Rights Reserved. +using System.Collections.Concurrent; using System.Reflection; using LightweightIocContainer.Exceptions; using LightweightIocContainer.Interfaces; @@ -21,8 +22,8 @@ public class IocContainer : IIocContainer, IIocResolver { private readonly RegistrationFactory _registrationFactory; - private readonly List<(Type type, object? instance)> _singletons = []; - private readonly List<(Type type, Type scope, Dictionary instances)> _multitons = []; + private readonly ConcurrentDictionary _singletons = []; + private readonly ConcurrentDictionary<(Type type, Type scope), ConcurrentDictionary> _multitons = []; private readonly List _ignoreConstructorAttributes = []; @@ -390,8 +391,8 @@ public class IocContainer : IIocContainer, IIocResolver else throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}."); - if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Singleton }) - _singletons.Add((GetType(registration), instance)); + if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Singleton }) + _singletons.TryAdd(GetType(registration), instance); if (registration is IOnCreate onCreateRegistration && instance is not null) onCreateRegistration.OnCreateAction?.Invoke(instance); @@ -429,8 +430,11 @@ public class IocContainer : IIocContainer, IIocResolver /// /// The /// A singleton instance if existing for the given , null if not - private object? TryGetSingletonInstance(IRegistration registration) => - _singletons.FirstOrDefault(s => s.type == GetType(registration)).instance; //if a singleton instance exists return it + private object? TryGetSingletonInstance(IRegistration registration) + { + _singletons.TryGetValue(GetType(registration), out object? value); //if a singleton instance exists return it + return value; + } /// /// Try to get an existing multiton instance for a given @@ -447,11 +451,11 @@ public class IocContainer : IIocContainer, IIocResolver object scopeArgument = TryGetMultitonScopeArgument(registration, arguments); //if a multiton for the given scope exists return it - var matchingMultitons = _multitons.FirstOrDefault(m => m.type == registration.ImplementationType && m.scope == registration.Scope); //get instances for the given type and scope (use implementation type to resolve the correct instance for multiple multiton registrations as well) - if (matchingMultitons == default) + bool foundMatchingMultitons = _multitons.TryGetValue((registration.ImplementationType, registration.Scope), out var matchingMultitons); //get instances for the given type and scope (use implementation type to resolve the correct instance for multiple multiton registrations as well) + if (!foundMatchingMultitons || matchingMultitons is null) return null; - return matchingMultitons.instances.TryGetValue(scopeArgument, out object? instance) && instance != null ? instance : null; + return matchingMultitons.TryGetValue(scopeArgument, out object? instance) && instance != null ? instance : null; } /// @@ -487,17 +491,21 @@ public class IocContainer : IIocContainer, IIocResolver object scopeArgument = TryGetMultitonScopeArgument(registration, arguments); //if a multiton for the given scope exists return it - var matchingMultitons = _multitons.FirstOrDefault(m => m.type == registration.ImplementationType && m.scope == registration.Scope); //get instances for the given type and scope (use implementation type to resolve the correct instance for multiple multiton registrations as well) - if (matchingMultitons != default) + bool foundMatchingMultitons = _multitons.TryGetValue((registration.ImplementationType, registration.Scope), out var matchingMultitons); + if (foundMatchingMultitons && matchingMultitons is not null) { T createdInstance = Creator.CreateInstance(registration.ImplementationType, arguments[1..]); - matchingMultitons.instances.Add(scopeArgument, createdInstance); + matchingMultitons.TryAdd(scopeArgument, createdInstance); return createdInstance; } T newInstance = Creator.CreateInstance(registration.ImplementationType, arguments[1..]); - _multitons.Add((registration.ImplementationType, registration.Scope, new Dictionary { { scopeArgument, newInstance } })); + + ConcurrentDictionary concurrentDictionary = new(); + concurrentDictionary.TryAdd(scopeArgument, newInstance); + + _multitons.TryAdd((registration.ImplementationType, registration.Scope), concurrentDictionary); return newInstance; } @@ -758,14 +766,8 @@ public class IocContainer : IIocContainer, IIocResolver IRegistration? registration = FindRegistration(); if (registration is not IMultitonRegistration multitonRegistration) return; - - var multitonInstance = _multitons.FirstOrDefault(m => m.type == multitonRegistration.ImplementationType); - - //it is allowed to clear a non existing multiton instance (don't throw an exception) - if (multitonInstance == default) - return; - - _multitons.Remove(multitonInstance); + + _multitons.Remove((multitonRegistration.ImplementationType, multitonRegistration.Scope), out _); } /// @@ -794,13 +796,13 @@ public class IocContainer : IIocContainer, IIocResolver /// public void Dispose() { - _singletons.Where(s => FindRegistration(s.type) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container}) - .Select(s => s.instance) + _singletons.Where(s => FindRegistration(s.Key) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container}) + .Select(s => s.Value) .OfType() .ForEach(d => d.Dispose()); - _multitons.Where(m => FindRegistration(m.type) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container}) - .SelectMany(m => m.instances) + _multitons.Where(m => FindRegistration(m.Key.type) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container}) + .SelectMany(m => m.Value) .Select(i => i.Value) .OfType() .ForEach(d => d.Dispose()); diff --git a/LightweightIocContainer/LightweightIocContainer.xml b/LightweightIocContainer/LightweightIocContainer.xml index 32746d5..af776ea 100644 --- a/LightweightIocContainer/LightweightIocContainer.xml +++ b/LightweightIocContainer/LightweightIocContainer.xml @@ -1946,6 +1946,11 @@ An internal placeholder that is used to hold factory methods for types that need to be resolved during the resolve process + + + An internal placeholder that is used to hold factory methods for types that need to be resolved during the resolve process + + The to be resolved @@ -1966,6 +1971,11 @@ An internal placeholder that is used to hold types that need to be resolved during the resolving process + + + An internal placeholder that is used to hold types that need to be resolved during the resolving process + + The to be resolved