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;
}
}
}