DefaultGenericHandler
using Castle.Core;
using Castle.Core.Internal;
using Castle.DynamicProxy;
using Castle.MicroKernel.ComponentActivator;
using Castle.MicroKernel.Context;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Castle.MicroKernel.Handlers
{
public class DefaultGenericHandler : AbstractHandler
{
private readonly IGenericImplementationMatchingStrategy implementationMatchingStrategy;
private readonly IGenericServiceStrategy serviceStrategy;
private readonly SimpleThreadSafeDictionary<Type, IHandler> type2SubHandler = new SimpleThreadSafeDictionary<Type, IHandler>();
public IGenericImplementationMatchingStrategy ImplementationMatchingStrategy => implementationMatchingStrategy;
public IGenericServiceStrategy ServiceStrategy => serviceStrategy;
public DefaultGenericHandler(ComponentModel model, IGenericImplementationMatchingStrategy implementationMatchingStrategy, IGenericServiceStrategy serviceStrategy)
: base(model)
{
this.implementationMatchingStrategy = implementationMatchingStrategy;
this.serviceStrategy = serviceStrategy;
}
public override void Dispose()
{
IHandler[] array = type2SubHandler.EjectAllValues();
IHandler[] array2 = array;
foreach (IHandler handler in array2) {
(handler as IDisposable)?.Dispose();
}
}
public override bool ReleaseCore(Burden burden)
{
Type unproxiedType = ProxyUtil.GetUnproxiedType(burden.Instance);
IHandler subHandler = GetSubHandler(CreationContext.CreateEmpty(), unproxiedType);
return subHandler.Release(burden);
}
public override bool Supports(Type service)
{
if (base.Supports(service))
return true;
if (type2SubHandler.Contains(service))
return true;
if (service.IsGenericType && !service.IsGenericTypeDefinition) {
Type genericTypeDefinition = service.GetGenericTypeDefinition();
if (!base.Supports(genericTypeDefinition))
return false;
if (serviceStrategy != null)
return serviceStrategy.Supports(service, base.ComponentModel);
return true;
}
return false;
}
public override bool SupportsAssignable(Type service)
{
if (base.SupportsAssignable(service))
return true;
if (!service.IsGenericType || service.IsGenericTypeDefinition)
return false;
Type[] serviceArguments = service.GetGenericArguments();
return base.ComponentModel.Services.Any((Type s) => SupportsAssignable(service, s, serviceArguments));
}
protected virtual Type[] AdaptServices(CreationContext context, Type closedImplementationType)
{
Type[] array = base.ComponentModel.Services.ToArray();
if (array.Length == 1 && (object)array[0] == context.RequestedType.GetGenericTypeDefinition())
return new Type[1] {
context.RequestedType
};
List<Type> list = new List<Type>(array.Length);
int num = AdaptClassServices(closedImplementationType, list, array);
if (num == array.Length - 1)
return list.ToArray();
AdaptInterfaceServices(closedImplementationType, list, array, num);
if (list.Count == 0)
return new Type[1] {
context.RequestedType
};
return list.ToArray();
}
protected virtual IHandler BuildSubHandler(CreationContext context, Type closedImplementationType)
{
ComponentModel componentModel = base.Kernel.ComponentModelBuilder.BuildModel(base.ComponentModel.ComponentName, AdaptServices(context, closedImplementationType), closedImplementationType, GetExtendedProperties());
CloneParentProperties(componentModel);
IKernelInternal kernel = base.Kernel;
bool isMetaHandler = true;
return kernel.AddCustomComponent(componentModel, isMetaHandler);
}
protected IHandler GetSubHandler(CreationContext context, Type genericType)
{
return type2SubHandler.GetOrAdd(genericType, (Type t) => BuildSubHandler(context, t));
}
protected override void InitDependencies()
{
IDependencyAwareActivator dependencyAwareActivator = base.Kernel.CreateComponentActivator(base.ComponentModel) as IDependencyAwareActivator;
if (dependencyAwareActivator == null || !dependencyAwareActivator.CanProvideRequiredDependencies(base.ComponentModel))
base.InitDependencies();
}
protected override object Resolve(CreationContext context, bool instanceRequired)
{
Type closedImplementationType = GetClosedImplementationType(context, instanceRequired);
if ((object)closedImplementationType == null)
return null;
IHandler subHandler = GetSubHandler(context, closedImplementationType);
using (context.EnterResolutionContext(this, false, false))
try {
return subHandler.Resolve(context);
} catch (GenericHandlerTypeMismatchException innerException) {
throw new HandlerException($"""{base.ComponentModel.Name}""", base.ComponentModel.ComponentName, innerException);
}
}
protected bool SupportsAssignable(Type service, Type modelService, Type[] serviceArguments)
{
if (!modelService.IsGenericTypeDefinition || modelService.GetGenericArguments().Length != serviceArguments.Length)
return false;
Type type = modelService.TryMakeGenericType(serviceArguments);
if ((object)type == null)
return false;
if (!service.IsAssignableFrom(type))
return false;
if (ServiceStrategy != null && !ServiceStrategy.Supports(type, base.ComponentModel))
return false;
return true;
}
private void CloneParentProperties(ComponentModel newModel)
{
newModel.LifestyleType = base.ComponentModel.LifestyleType;
foreach (InterceptorReference interceptor in base.ComponentModel.Interceptors) {
newModel.Interceptors.AddIfNotInCollection(interceptor);
}
if (base.ComponentModel.HasCustomDependencies) {
IDictionary customDependencies = newModel.CustomDependencies;
IDictionaryEnumerator enumerator2 = base.ComponentModel.CustomDependencies.GetEnumerator();
try {
while (enumerator2.MoveNext()) {
DictionaryEntry dictionaryEntry = (DictionaryEntry)enumerator2.Current;
customDependencies.Add(dictionaryEntry.Key, dictionaryEntry.Value);
}
} finally {
(enumerator2 as IDisposable)?.Dispose();
}
}
}
private Type GetClosedImplementationType(CreationContext context, bool instanceRequired)
{
Type[] genericArguments = GetGenericArguments(context);
try {
return base.ComponentModel.Implementation.MakeGenericType(genericArguments);
} catch (ArgumentNullException) {
if (implementationMatchingStrategy == null)
throw;
throw new HandlerException(string.Format("Custom {0} ({1}) didn't select any generic parameters for implementation type of component '{2}'. This usually signifies bug in the {0}.", typeof(IGenericImplementationMatchingStrategy).Name, implementationMatchingStrategy, base.ComponentModel.Name), base.ComponentModel.ComponentName);
} catch (ArgumentException innerException) {
if (instanceRequired) {
Type[] genericArguments2 = base.ComponentModel.Implementation.GetGenericArguments();
if (genericArguments2.Length > genericArguments.Length) {
string str = $"""{context.RequestedType}""{context.GenericArguments.Length}""{base.ComponentModel.Implementation}""{genericArguments2.Length}""{Environment.NewLine}""";
str = ((implementationMatchingStrategy != null) ? (str + string.Format("{0}This is most likely a bug in the {1} implementation this component uses ({2}).{0}Please consut the documentation for examples of how to implement it properly.", Environment.NewLine, typeof(IGenericImplementationMatchingStrategy).Name, implementationMatchingStrategy)) : (str + string.Format("{0}You can instruct Windsor which types it should use to close this generic component by supplying an implementation of {1}.{0}Please consut the documentation for examples of how to do that.", Environment.NewLine, typeof(IGenericImplementationMatchingStrategy).Name)));
throw new HandlerException(str, base.ComponentModel.ComponentName, innerException);
}
string[] array = (from t in genericArguments.Where(delegate(Type a) {
if (!a.IsPointer && !a.IsByRef)
return (object)a == typeof(void);
return true;
})
select t.FullName).ToArray();
if (array.Length > 0) {
string str = string.Format("The following types provided as generic parameters are not legal: {0}. This is most likely a bug in your code.", string.Join(", ", array));
throw new HandlerException(str, base.ComponentModel.ComponentName, innerException);
}
throw new GenericHandlerTypeMismatchException(genericArguments, base.ComponentModel, this);
}
return null;
}
}
private IDictionary GetExtendedProperties()
{
IDictionary dictionary = base.ComponentModel.ExtendedProperties;
if (dictionary != null && dictionary.Count > 0)
dictionary = new Arguments(dictionary);
return dictionary;
}
private Type[] GetGenericArguments(CreationContext context)
{
if (implementationMatchingStrategy == null)
return context.GenericArguments;
return implementationMatchingStrategy.GetGenericArguments(base.ComponentModel, context) ?? context.GenericArguments;
}
private static int AdaptClassServices(Type closedImplementationType, List<Type> closedServices, Type[] openServices)
{
int i = 0;
IDictionary<Type, Type> genericDefinitionToClass = null;
for (; i < openServices.Length && openServices[i].IsClass; i++) {
Type type = openServices[i];
if (type.IsGenericTypeDefinition) {
EnsureClassMappingInitialized(closedImplementationType, ref genericDefinitionToClass);
if (genericDefinitionToClass.TryGetValue(type, out Type value))
closedServices.Add(value);
} else
closedServices.Add(type);
}
return i;
}
private static void AdaptInterfaceServices(Type closedImplementationType, List<Type> closedServices, Type[] openServices, int index)
{
IDictionary<Type, Type> genericDefinitionToInterface = null;
while (index < openServices.Length) {
Type type = openServices[index];
if (type.IsGenericTypeDefinition) {
EnsureInterfaceMappingInitialized(closedImplementationType, ref genericDefinitionToInterface);
if (genericDefinitionToInterface.TryGetValue(type, out Type value))
closedServices.Add(value);
} else
closedServices.Add(type);
index++;
}
}
private static void EnsureClassMappingInitialized(Type closedImplementationType, ref IDictionary<Type, Type> genericDefinitionToClass)
{
if (genericDefinitionToClass == null) {
genericDefinitionToClass = new Dictionary<Type, Type>();
Type type = closedImplementationType;
while ((object)type != typeof(object)) {
if (type.IsGenericType)
genericDefinitionToClass.Add(type.GetGenericTypeDefinition(), type);
type = type.BaseType;
}
}
}
private static void EnsureInterfaceMappingInitialized(Type closedImplementationType, ref IDictionary<Type, Type> genericDefinitionToInterface)
{
if (genericDefinitionToInterface == null)
genericDefinitionToInterface = (from i in closedImplementationType.GetInterfaces()
where i.IsGenericType
select i).ToDictionary((Type i) => i.GetGenericTypeDefinition());
}
}
}