#13: use concurrentDictionaries to allow access from multiple threads

master
Simon G. 1 year ago
parent 45125eb926
commit eab71214f4
Signed by: SimonG
GPG Key ID: 0B82B964BA536523
  1. 1
      LightweightIocContainer.Validation/LightweightIocContainer.Validation.xml
  2. 48
      LightweightIocContainer/IocContainer.cs
  3. 10
      LightweightIocContainer/LightweightIocContainer.xml

@ -13,7 +13,6 @@
<summary> <summary>
Validator for your <see cref="T:LightweightIocContainer.IocContainer"/> to check if everything can be resolved with your current setup Validator for your <see cref="T:LightweightIocContainer.IocContainer"/> to check if everything can be resolved with your current setup
</summary> </summary>
<param name="iocContainer">The <see cref="T:LightweightIocContainer.IocContainer"/></param>
</member> </member>
<member name="M:LightweightIocContainer.Validation.IocValidator.AddParameter``2(``1)"> <member name="M:LightweightIocContainer.Validation.IocValidator.AddParameter``2(``1)">
<summary> <summary>

@ -2,6 +2,7 @@
// Created: 2019-05-20 // Created: 2019-05-20
// Copyright(c) 2019 SimonG. All Rights Reserved. // Copyright(c) 2019 SimonG. All Rights Reserved.
using System.Collections.Concurrent;
using System.Reflection; using System.Reflection;
using LightweightIocContainer.Exceptions; using LightweightIocContainer.Exceptions;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
@ -21,8 +22,8 @@ public class IocContainer : IIocContainer, IIocResolver
{ {
private readonly RegistrationFactory _registrationFactory; private readonly RegistrationFactory _registrationFactory;
private readonly List<(Type type, object? instance)> _singletons = []; private readonly ConcurrentDictionary<Type, object?> _singletons = [];
private readonly List<(Type type, Type scope, Dictionary<object, object?> instances)> _multitons = []; private readonly ConcurrentDictionary<(Type type, Type scope), ConcurrentDictionary<object, object?>> _multitons = [];
private readonly List<Type> _ignoreConstructorAttributes = []; private readonly List<Type> _ignoreConstructorAttributes = [];
@ -391,7 +392,7 @@ public class IocContainer : IIocContainer, IIocResolver
throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}."); throw new UnknownRegistrationException($"There is no registration of type {registration.GetType().Name}.");
if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Singleton }) if (registration is ILifestyleProvider { Lifestyle: Lifestyle.Singleton })
_singletons.Add((GetType<T>(registration), instance)); _singletons.TryAdd(GetType<T>(registration), instance);
if (registration is IOnCreate onCreateRegistration && instance is not null) if (registration is IOnCreate onCreateRegistration && instance is not null)
onCreateRegistration.OnCreateAction?.Invoke(instance); onCreateRegistration.OnCreateAction?.Invoke(instance);
@ -429,8 +430,11 @@ public class IocContainer : IIocContainer, IIocResolver
/// </summary> /// </summary>
/// <param name="registration">The <see cref="IRegistration"/></param> /// <param name="registration">The <see cref="IRegistration"/></param>
/// <returns>A singleton instance if existing for the given <see cref="IRegistration"/>, null if not</returns> /// <returns>A singleton instance if existing for the given <see cref="IRegistration"/>, null if not</returns>
private object? TryGetSingletonInstance<T>(IRegistration registration) => private object? TryGetSingletonInstance<T>(IRegistration registration)
_singletons.FirstOrDefault(s => s.type == GetType<T>(registration)).instance; //if a singleton instance exists return it {
_singletons.TryGetValue(GetType<T>(registration), out object? value); //if a singleton instance exists return it
return value;
}
/// <summary> /// <summary>
/// Try to get an existing multiton instance for a given <see cref="IMultitonRegistration"/> /// Try to get an existing multiton instance for a given <see cref="IMultitonRegistration"/>
@ -447,11 +451,11 @@ public class IocContainer : IIocContainer, IIocResolver
object scopeArgument = TryGetMultitonScopeArgument(registration, arguments); object scopeArgument = TryGetMultitonScopeArgument(registration, arguments);
//if a multiton for the given scope exists return it //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) 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 (matchingMultitons == default) if (!foundMatchingMultitons || matchingMultitons is null)
return 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;
} }
/// <summary> /// <summary>
@ -487,17 +491,21 @@ public class IocContainer : IIocContainer, IIocResolver
object scopeArgument = TryGetMultitonScopeArgument(registration, arguments); object scopeArgument = TryGetMultitonScopeArgument(registration, arguments);
//if a multiton for the given scope exists return it //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) bool foundMatchingMultitons = _multitons.TryGetValue((registration.ImplementationType, registration.Scope), out var matchingMultitons);
if (matchingMultitons != default) if (foundMatchingMultitons && matchingMultitons is not null)
{ {
T createdInstance = Creator.CreateInstance<T>(registration.ImplementationType, arguments[1..]); T createdInstance = Creator.CreateInstance<T>(registration.ImplementationType, arguments[1..]);
matchingMultitons.instances.Add(scopeArgument, createdInstance); matchingMultitons.TryAdd(scopeArgument, createdInstance);
return createdInstance; return createdInstance;
} }
T newInstance = Creator.CreateInstance<T>(registration.ImplementationType, arguments[1..]); T newInstance = Creator.CreateInstance<T>(registration.ImplementationType, arguments[1..]);
_multitons.Add((registration.ImplementationType, registration.Scope, new Dictionary<object, object?> { { scopeArgument, newInstance } }));
ConcurrentDictionary<object,object?> concurrentDictionary = new();
concurrentDictionary.TryAdd(scopeArgument, newInstance);
_multitons.TryAdd((registration.ImplementationType, registration.Scope), concurrentDictionary);
return newInstance; return newInstance;
} }
@ -759,13 +767,7 @@ public class IocContainer : IIocContainer, IIocResolver
if (registration is not IMultitonRegistration multitonRegistration) if (registration is not IMultitonRegistration multitonRegistration)
return; return;
var multitonInstance = _multitons.FirstOrDefault(m => m.type == multitonRegistration.ImplementationType); _multitons.Remove((multitonRegistration.ImplementationType, multitonRegistration.Scope), out _);
//it is allowed to clear a non existing multiton instance (don't throw an exception)
if (multitonInstance == default)
return;
_multitons.Remove(multitonInstance);
} }
/// <summary> /// <summary>
@ -794,13 +796,13 @@ public class IocContainer : IIocContainer, IIocResolver
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
_singletons.Where(s => FindRegistration(s.type) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container}) _singletons.Where(s => FindRegistration(s.Key) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container})
.Select(s => s.instance) .Select(s => s.Value)
.OfType<IDisposable>() .OfType<IDisposable>()
.ForEach(d => d.Dispose()); .ForEach(d => d.Dispose());
_multitons.Where(m => FindRegistration(m.type) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container}) _multitons.Where(m => FindRegistration(m.Key.type) is IWithDisposeStrategyInternal {DisposeStrategy: DisposeStrategy.Container})
.SelectMany(m => m.instances) .SelectMany(m => m.Value)
.Select(i => i.Value) .Select(i => i.Value)
.OfType<IDisposable>() .OfType<IDisposable>()
.ForEach(d => d.Dispose()); .ForEach(d => d.Dispose());

@ -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
</summary> </summary>
</member> </member>
<member name="M:LightweightIocContainer.ResolvePlaceholders.InternalFactoryMethodPlaceholder`1.#ctor(LightweightIocContainer.Interfaces.Registrations.ISingleTypeRegistration{`0})">
<summary>
An internal placeholder that is used to hold factory methods for types that need to be resolved during the resolve process
</summary>
</member>
<member name="P:LightweightIocContainer.ResolvePlaceholders.InternalFactoryMethodPlaceholder`1.ResolvedType"> <member name="P:LightweightIocContainer.ResolvePlaceholders.InternalFactoryMethodPlaceholder`1.ResolvedType">
<summary> <summary>
The <see cref="T:System.Type"/> to be resolved The <see cref="T:System.Type"/> 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
</summary> </summary>
</member> </member>
<member name="M:LightweightIocContainer.ResolvePlaceholders.InternalToBeResolvedPlaceholder.#ctor(System.Type,LightweightIocContainer.Interfaces.Registrations.IRegistration,System.Collections.Generic.List{System.Object})">
<summary>
An internal placeholder that is used to hold types that need to be resolved during the resolving process
</summary>
</member>
<member name="P:LightweightIocContainer.ResolvePlaceholders.InternalToBeResolvedPlaceholder.ResolvedType"> <member name="P:LightweightIocContainer.ResolvePlaceholders.InternalToBeResolvedPlaceholder.ResolvedType">
<summary> <summary>
The <see cref="T:System.Type"/> to be resolved The <see cref="T:System.Type"/> to be resolved

Loading…
Cancel
Save