DefaultGenericHandler
using Castle.Core;
using Castle.Core.Internal;
using Castle.DynamicProxy;
using Castle.MicroKernel.ComponentActivator;
using Castle.MicroKernel.Context;
using Castle.MicroKernel.ModelBuilder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Castle.MicroKernel.Handlers
{
[Serializable]
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();
for (int i = 0; i < array.Length; i++) {
(array[i] as IDisposable)?.Dispose();
}
}
public override bool ReleaseCore(Burden burden)
{
Type unproxiedType = ProxyUtil.GetUnproxiedType(burden.Instance);
return type2SubHandler.GetOrThrow(unproxiedType).Release(burden);
}
public override bool Supports(Type service)
{
if (base.Supports(service))
return true;
if (type2SubHandler.Contains(service))
return true;
if (service.GetTypeInfo().IsGenericType && !service.GetTypeInfo().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.GetTypeInfo().IsGenericType || service.GetTypeInfo().IsGenericTypeDefinition)
return false;
Type[] serviceArguments = service.GetGenericArguments();
return base.ComponentModel.Services.Any((Type s) => SupportsAssignable(service, s, serviceArguments));
}
protected virtual Type[] AdaptServices(Type closedImplementationType, Type requestedType)
{
Type[] array = base.ComponentModel.Services.ToArray();
if (array.Length == 1 && requestedType.GetTypeInfo().IsGenericType && array[0] == requestedType.GetGenericTypeDefinition())
return new Type[1] {
requestedType
};
List<Type> list = new List<Type>(array.Length);
int num = AdaptClassServices(closedImplementationType, list, array);
if (num == array.Length - 1 && list.Count > 0)
return list.ToArray();
AdaptInterfaceServices(closedImplementationType, list, array, num);
if (list.Count == 0)
return new Type[1] {
requestedType
};
return list.ToArray();
}
protected virtual IHandler BuildSubHandler(Type closedImplementationType, Type requestedType)
{
ComponentModel componentModel = base.Kernel.ComponentModelBuilder.BuildModel(base.ComponentModel.ComponentName, AdaptServices(closedImplementationType, requestedType), closedImplementationType, GetExtendedProperties());
CloneParentProperties(componentModel);
return base.Kernel.CreateHandler(componentModel);
}
protected IHandler GetSubHandler(Type genericType, Type requestedType)
{
bool added = false;
IHandler orAdd = type2SubHandler.GetOrAdd(genericType, delegate(Type t) {
added = true;
return BuildSubHandler(t, requestedType);
});
if (added)
base.Kernel.RaiseEventsOnHandlerCreated(orAdd);
return orAdd;
}
protected override void InitDependencies()
{
IDependencyAwareActivator dependencyAwareActivator = base.Kernel.CreateComponentActivator(base.ComponentModel) as IDependencyAwareActivator;
if (dependencyAwareActivator != null && dependencyAwareActivator.CanProvideRequiredDependencies(base.ComponentModel)) {
foreach (DependencyModel dependency in base.ComponentModel.Dependencies) {
dependency.Init(base.ComponentModel.ParametersInternal);
}
} else
base.InitDependencies();
}
protected override object Resolve(CreationContext context, bool instanceRequired)
{
Type closedImplementationType = GetClosedImplementationType(context, instanceRequired);
if (closedImplementationType == (Type)null)
return null;
IHandler subHandler = GetSubHandler(closedImplementationType, context.RequestedType);
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.GetTypeInfo().IsGenericTypeDefinition || modelService.GetGenericArguments().Length != serviceArguments.Length)
return false;
Type type = modelService.TryMakeGenericType(serviceArguments);
if (type == (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) {
Arguments customDependencies = newModel.CustomDependencies;
foreach (KeyValuePair<object, object> customDependency in base.ComponentModel.CustomDependencies) {
customDependencies.Add(customDependency.Key, customDependency.Value);
}
}
ICollection<IMetaComponentModelDescriptor> metaDescriptors = base.ComponentModel.GetMetaDescriptors(false);
if (metaDescriptors != null) {
foreach (IMetaComponentModelDescriptor item in metaDescriptors) {
item.ConfigureComponentModel(base.Kernel, newModel);
}
}
}
public IHandler ConvertToClosedGenericHandler(Type service, CreationContext openGenericContext)
{
Type closedImplementationType = GetClosedImplementationType(openGenericContext, false);
return GetSubHandler(closedImplementationType, service);
}
private Type GetClosedImplementationType(CreationContext context, bool instanceRequired)
{
if (!(base.ComponentModel.Implementation == typeof(LateBoundComponent))) {
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 consult 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 consult 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 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;
}
}
return context.RequestedType;
}
private Arguments GetExtendedProperties()
{
Arguments arguments = base.ComponentModel.ExtendedProperties;
if (arguments != null && arguments.Count > 0)
arguments = new Arguments(arguments);
return arguments;
}
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].GetTypeInfo().IsClass; i++) {
Type type = openServices[i];
if (type.GetTypeInfo().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.GetTypeInfo().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 (type != typeof(object)) {
if (type.GetTypeInfo().IsGenericType)
genericDefinitionToClass.Add(type.GetGenericTypeDefinition(), type);
type = type.GetTypeInfo().BaseType;
}
}
}
private static void EnsureInterfaceMappingInitialized(Type closedImplementationType, ref IDictionary<Type, Type> genericDefinitionToInterface)
{
if (genericDefinitionToInterface == null)
genericDefinitionToInterface = (from i in closedImplementationType.GetInterfaces()
where i.GetTypeInfo().IsGenericType
select i).ToDictionary((Type i) => i.GetGenericTypeDefinition());
}
}
}