Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="4.2.0-preview-690" />

 RegistrationRepository

using Stashbox.Configuration; using Stashbox.Exceptions; using Stashbox.Registration.Extensions; using Stashbox.Registration.SelectionRules; using Stashbox.Resolution; using Stashbox.Utils; using Stashbox.Utils.Data; using Stashbox.Utils.Data.Immutable; using System; using System.Collections.Generic; using System.Linq; namespace Stashbox.Registration { internal class RegistrationRepository : IRegistrationRepository { private ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> serviceRepository = ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>.Empty; private readonly ContainerConfiguration containerConfiguration; private readonly IRegistrationSelectionRule[] filters = new IRegistrationSelectionRule[4] { RegistrationSelectionRules.GenericFilter, RegistrationSelectionRules.NameFilter, RegistrationSelectionRules.ScopeNameFilter, RegistrationSelectionRules.ConditionFilter }; private readonly IRegistrationSelectionRule[] topLevelFilters = new IRegistrationSelectionRule[3] { RegistrationSelectionRules.GenericFilter, RegistrationSelectionRules.NameFilter, RegistrationSelectionRules.ScopeNameFilter }; private readonly IRegistrationSelectionRule[] enumerableFilters = new IRegistrationSelectionRule[3] { RegistrationSelectionRules.GenericFilter, RegistrationSelectionRules.ScopeNameFilter, RegistrationSelectionRules.ConditionFilter }; public RegistrationRepository(ContainerConfiguration containerConfiguration) { this.containerConfiguration = containerConfiguration; } public bool AddOrUpdateRegistration(ServiceRegistration registration, Type serviceType) { if (registration.RegistrationContext.ReplaceExistingRegistrationOnlyIfExists) return Swap.SwapValue<ServiceRegistration, Type, byte, byte, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>>(ref serviceRepository, (ServiceRegistration reg, Type type, byte _, byte _, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.UpdateIfExists(type, true, (ImmutableBucket<object, ServiceRegistration> regs) => regs.ReplaceIfExists(reg.RegistrationDiscriminator, reg, false, delegate(ServiceRegistration old, ServiceRegistration new) { new.Replaces(old); return new; })), registration, serviceType, 0, 0); return Swap.SwapValue(ref serviceRepository, (ServiceRegistration reg, Type type, ImmutableBucket<object, ServiceRegistration> newRepo, Rules.RegistrationBehavior regBehavior, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.AddOrUpdate(type, newRepo, true, delegate(ImmutableBucket<object, ServiceRegistration> oldValue, ImmutableBucket<object, ServiceRegistration> _) { bool allowUpdate = reg.RegistrationContext.ReplaceExistingRegistration || regBehavior == Rules.RegistrationBehavior.ReplaceExisting; if (!allowUpdate && regBehavior == Rules.RegistrationBehavior.PreserveDuplications) return oldValue.Add(reg.RegistrationDiscriminator, reg); return oldValue.AddOrUpdate(reg.RegistrationDiscriminator, reg, false, delegate(ServiceRegistration old, ServiceRegistration new) { if (!allowUpdate) { if (regBehavior == Rules.RegistrationBehavior.ThrowException) throw new ServiceAlreadyRegisteredException(old.ImplementationType, null); return old; } new.Replaces(old); return new; }); }), registration, serviceType, new ImmutableBucket<object, ServiceRegistration>(registration.RegistrationDiscriminator, registration), containerConfiguration.RegistrationBehavior); } public bool AddOrReMapRegistration(ServiceRegistration registration, Type serviceType) { if (!registration.RegistrationContext.ReplaceExistingRegistrationOnlyIfExists) return Swap.SwapValue<Type, ImmutableBucket<object, ServiceRegistration>, byte, byte, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>>(ref serviceRepository, (Type type, ImmutableBucket<object, ServiceRegistration> newRepo, byte _, byte _, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.AddOrUpdate(type, newRepo, true, true), serviceType, new ImmutableBucket<object, ServiceRegistration>(registration.RegistrationDiscriminator, registration), 0, 0); return Swap.SwapValue<Type, ImmutableBucket<object, ServiceRegistration>, byte, byte, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>>(ref serviceRepository, (Type type, ImmutableBucket<object, ServiceRegistration> newRepo, byte _, byte _, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.UpdateIfExists(type, newRepo, true), serviceType, new ImmutableBucket<object, ServiceRegistration>(registration.RegistrationDiscriminator, registration), 0, 0); } public bool ContainsRegistration(Type type, object name, bool includeOpenGenerics = false) { return serviceRepository.ContainsRegistration(type, name, includeOpenGenerics); } public IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings() { return serviceRepository.Walk().SelectMany((KeyValue<Type, ImmutableBucket<object, ServiceRegistration>> reg) => from r in reg.Value select new KeyValuePair<Type, ServiceRegistration>(reg.Key, r)); } public ServiceRegistration GetRegistrationOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext) { IEnumerable<ServiceRegistration> registrationsForType = GetRegistrationsForType(typeInfo.Type); if (registrationsForType == null) return null; return registrationsForType.SelectOrDefault(typeInfo, resolutionContext, resolutionContext.IsTopRequest ? topLevelFilters : filters); } public IEnumerable<ServiceRegistration> GetRegistrationsOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext) { IEnumerable<ServiceRegistration> registrationsForType = GetRegistrationsForType(typeInfo.Type); if (registrationsForType == null) return null; IEnumerable<ServiceRegistration> enumerable = registrationsForType.FilterExclusiveOrDefault(typeInfo, resolutionContext, enumerableFilters); if (enumerable == null) return null; return from reg in enumerable orderby reg.RegistrationOrder select reg; } private IEnumerable<ServiceRegistration> GetRegistrationsForType(Type type) { IEnumerable<ServiceRegistration> enumerable = serviceRepository.GetOrDefaultByRef(type); if (!type.IsClosedGenericType()) return enumerable; ImmutableBucket<object, ServiceRegistration> orDefaultByRef = serviceRepository.GetOrDefaultByRef(type.GetGenericTypeDefinition()); if (orDefaultByRef != null) { object enumerable2; if (enumerable != null) enumerable2 = orDefaultByRef.Concat(enumerable); else { IEnumerable<ServiceRegistration> enumerable3 = orDefaultByRef; enumerable2 = enumerable3; } enumerable = (IEnumerable<ServiceRegistration>)enumerable2; } ServiceRegistration[] array = serviceRepository.Walk().Where(delegate(KeyValue<Type, ImmutableBucket<object, ServiceRegistration>> r) { if (r.Key.IsGenericType && r.Key.GetGenericTypeDefinition() == type.GetGenericTypeDefinition() && r.Key != type) return r.Key.ImplementsWithoutGenericCheck(type); return false; }).SelectMany((KeyValue<Type, ImmutableBucket<object, ServiceRegistration>> r) => r.Value) .ToArray(); if (array.Length != 0) { object enumerable4; if (enumerable != null) enumerable4 = array.Concat(enumerable); else { IEnumerable<ServiceRegistration> enumerable3 = array; enumerable4 = enumerable3; } enumerable = (IEnumerable<ServiceRegistration>)enumerable4; } return enumerable; } } }