Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="3.4.1-preview-606" />

 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 t3, byte t4, 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> newValue) { 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 && regBehavior == Rules.RegistrationBehavior.ThrowException) throw new ServiceAlreadyRegisteredException(old.ImplementationType, null); if (!allowUpdate) 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 t3, byte t4, 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 t3, byte t4, 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) { return serviceRepository.ContainsRegistration(type, name); } 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(Type type, ResolutionContext resolutionContext, object name = null) { IEnumerable<ServiceRegistration> registrationsForType = GetRegistrationsForType(type); if (registrationsForType == null) return null; return registrationsForType.SelectOrDefault(new TypeInformation(type, name), resolutionContext, topLevelFilters); } public ServiceRegistration GetRegistrationOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext) { IEnumerable<ServiceRegistration> registrationsForType = GetRegistrationsForType(typeInfo.Type); if (registrationsForType == null) return null; return registrationsForType.SelectOrDefault(typeInfo, resolutionContext, 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.RegistrationId select reg; } private IEnumerable<ServiceRegistration> GetRegistrationsForType(Type type) { ImmutableBucket<object, ServiceRegistration> orDefault = serviceRepository.GetOrDefault(type, true); if (!type.IsClosedGenericType()) return orDefault; ImmutableBucket<object, ServiceRegistration> orDefault2 = serviceRepository.GetOrDefault(type.GetGenericTypeDefinition(), true); if (orDefault2 == null) return orDefault; if (orDefault != null) return orDefault2.Concat(orDefault); return orDefault2; } } }