<PackageReference Include="Castle.Windsor" Version="5.1.1" />

DefaultNamingSubSystem

using Castle.Core.Internal; using Castle.MicroKernel.Internal; using Castle.MicroKernel.Util; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace Castle.MicroKernel.SubSystems.Naming { [Serializable] public class DefaultNamingSubSystem : AbstractSubSystem, INamingSubSystem, ISubSystem { protected struct HandlerWithPriority { private readonly IHandler handler; private readonly int priority; public IHandler Handler => handler; public HandlerWithPriority(int priority, IHandler handler) { this.priority = priority; this.handler = handler; } public bool Triumphs(HandlerWithPriority other) { if (priority > other.priority) return true; if (priority == other.priority && priority > 0) return true; return false; } } protected readonly Castle.MicroKernel.Internal.Lock lock = Castle.MicroKernel.Internal.Lock.Create(); protected readonly Dictionary<string, IHandler> name2Handler = new Dictionary<string, IHandler>(StringComparer.OrdinalIgnoreCase); protected readonly Dictionary<Type, HandlerWithPriority> service2Handler = new Dictionary<Type, HandlerWithPriority>(SimpleTypeEqualityComparer.Instance); protected IList<IHandlersFilter> filters; protected IList<IHandlerSelector> selectors; private readonly IDictionary<Type, IHandler[]> assignableHandlerListsByTypeCache = new Dictionary<Type, IHandler[]>(SimpleTypeEqualityComparer.Instance); protected readonly IDictionary<Type, IHandler[]> handlerListsByTypeCache = new Dictionary<Type, IHandler[]>(SimpleTypeEqualityComparer.Instance); private Dictionary<string, IHandler> handlerByNameCache; private Dictionary<Type, IHandler> handlerByServiceCache; public virtual int ComponentCount => HandlerByNameCache.Count; protected IDictionary<string, IHandler> HandlerByNameCache { get { Dictionary<string, IHandler> dictionary = handlerByNameCache; if (dictionary != null) return dictionary; using (lock.ForWriting()) return handlerByNameCache = new Dictionary<string, IHandler>(name2Handler, name2Handler.Comparer); } } protected IDictionary<Type, IHandler> HandlerByServiceCache { get { Dictionary<Type, IHandler> dictionary = handlerByServiceCache; if (dictionary != null) return dictionary; using (lock.ForWriting()) { dictionary = new Dictionary<Type, IHandler>(service2Handler.Count, service2Handler.Comparer); foreach (KeyValuePair<Type, HandlerWithPriority> item in service2Handler) { dictionary.Add(item.Key, item.Value.Handler); } handlerByServiceCache = dictionary; return dictionary; } } } public void AddHandlerSelector(IHandlerSelector selector) { if (selectors == null) selectors = new List<IHandlerSelector>(); selectors.Add(selector); } public void AddHandlersFilter(IHandlersFilter filter) { if (filters == null) filters = new List<IHandlersFilter>(); filters.Add(filter); } public virtual bool Contains(string name) { return HandlerByNameCache.ContainsKey(name); } public virtual bool Contains(Type service) { return GetHandler(service) != null; } public virtual IHandler[] GetAllHandlers() { IDictionary<string, IHandler> dictionary = HandlerByNameCache; IHandler[] array = new IHandler[dictionary.Values.Count]; dictionary.Values.CopyTo(array, 0); return array; } public virtual IHandler[] GetAssignableHandlers(Type service) { if (service == (Type)null) throw new ArgumentNullException("service"); if (service == typeof(object)) return GetAllHandlers(); return GetAssignableHandlersNoFiltering(service); } public virtual IHandler GetHandler(string name) { if (name == null) throw new ArgumentNullException("name"); if (selectors != null) { IHandler selectorsOpinion = GetSelectorsOpinion(name, null); if (selectorsOpinion != null) return selectorsOpinion; } HandlerByNameCache.TryGetValue(name, out IHandler value); return value; } public virtual IHandler GetHandler(Type service) { if (service == (Type)null) throw new ArgumentNullException("service"); if (selectors != null) { IHandler selectorsOpinion = GetSelectorsOpinion(null, service); if (selectorsOpinion != null) return selectorsOpinion; } if (HandlerByServiceCache.TryGetValue(service, out IHandler value)) return value; if (service.GetTypeInfo().IsGenericType && !service.GetTypeInfo().IsGenericTypeDefinition) { Type genericTypeDefinition = service.GetGenericTypeDefinition(); if (HandlerByServiceCache.TryGetValue(genericTypeDefinition, out value) && value.Supports(service)) return value; IHandler[] handlers = GetHandlers(genericTypeDefinition); foreach (IHandler handler in handlers) { if (handler.Supports(service)) return handler; } } return null; } public virtual IHandler[] GetHandlers(Type service) { if (service == (Type)null) throw new ArgumentNullException("service"); if (filters != null) { IHandler[] filtersOpinion = GetFiltersOpinion(service); if (filtersOpinion != null) return filtersOpinion; } using (Castle.MicroKernel.Internal.IUpgradeableLockHolder upgradeableLockHolder = lock.ForReadingUpgradeable()) { if (!handlerListsByTypeCache.TryGetValue(service, out IHandler[] value)) { value = GetHandlersNoLock(service); upgradeableLockHolder.Upgrade(); handlerListsByTypeCache[service] = value; return value; } return value; } } public virtual void Register(IHandler handler) { string name = handler.ComponentModel.Name; using (lock.ForWriting()) { try { name2Handler.Add(name, handler); } catch (ArgumentException) { throw new ComponentRegistrationException($"""{name}"""); } Func<Type, HandlerWithPriority> serviceSelector = GetServiceSelector(handler); foreach (Type service in handler.ComponentModel.Services) { HandlerWithPriority value = serviceSelector(service); if (!service2Handler.TryGetValue(service, out HandlerWithPriority value2) || value.Triumphs(value2)) service2Handler[service] = value; } InvalidateCache(); } } protected IHandler[] GetAssignableHandlersNoFiltering(Type service) { using (Castle.MicroKernel.Internal.IUpgradeableLockHolder upgradeableLockHolder = lock.ForReadingUpgradeable()) { if (!assignableHandlerListsByTypeCache.TryGetValue(service, out IHandler[] value)) { upgradeableLockHolder.Upgrade(); if (!assignableHandlerListsByTypeCache.TryGetValue(service, out value)) { value = (from h in name2Handler.Values where h.SupportsAssignable(service) select h).ToArray(); assignableHandlerListsByTypeCache[service] = value; return value; } return value; } return value; } } protected virtual IHandler[] GetFiltersOpinion(Type service) { if (filters == null) return null; IHandler[] array = null; foreach (IHandlersFilter filter in filters) { if (filter.HasOpinionAbout(service)) { if (array == null) array = GetAssignableHandlersNoFiltering(service); array = filter.SelectHandlers(service, array); if (array != null) return array; } } return null; } protected virtual IHandler GetSelectorsOpinion(string name, Type type) { if (selectors == null) return null; type = (type ?? typeof(object)); IHandler[] array = null; foreach (IHandlerSelector selector in selectors) { if (selector.HasOpinionAbout(name, type)) { if (array == null) array = GetAssignableHandlersNoFiltering(type); IHandler handler = selector.SelectHandler(name, type, array); if (handler != null) return handler; } } return null; } protected void InvalidateCache() { handlerListsByTypeCache.Clear(); assignableHandlerListsByTypeCache.Clear(); handlerByNameCache = null; handlerByServiceCache = null; } private IHandler[] GetHandlersNoLock(Type service) { SegmentedList<IHandler> segmentedList = new SegmentedList<IHandler>(3); foreach (IHandler value in name2Handler.Values) { if (value.Supports(service)) { if (IsDefault(value, service)) segmentedList.AddFirst(0, value); else if (IsFallback(value, service)) { segmentedList.AddLast(2, value); } else { segmentedList.AddLast(1, value); } } } return segmentedList.ToArray(); } private Func<Type, HandlerWithPriority> GetServiceSelector(IHandler handler) { Predicate<Type> defaultsFilter = handler.ComponentModel.GetDefaultComponentForServiceFilter(); Predicate<Type> fallbackFilter = handler.ComponentModel.GetFallbackComponentForServiceFilter(); if (defaultsFilter == null) { if (fallbackFilter == null) return (Type service) => new HandlerWithPriority(0, handler); return (Type service) => new HandlerWithPriority(fallbackFilter(service) ? (-1) : 0, handler); } if (fallbackFilter == null) return (Type service) => new HandlerWithPriority(defaultsFilter(service) ? 1 : 0, handler); return (Type service) => new HandlerWithPriority(defaultsFilter(service) ? 1 : (fallbackFilter(service) ? (-1) : 0), handler); } private bool IsDefault(IHandler handler, Type service) { return handler.ComponentModel.GetDefaultComponentForServiceFilter()?.Invoke(service) ?? false; } private bool IsFallback(IHandler handler, Type service) { return handler.ComponentModel.GetFallbackComponentForServiceFilter()?.Invoke(service) ?? false; } } }