Я пишу решатель зависимостей для замка Виндзор. Средство распознавания возвращает объект, который реализует универсальный интерфейс. Общие параметры разрешаются во время выполнения, а фабрика используется для возврата правильной реализации. Я не хочу использовать строку, чтобы получить MethodInfo фабричного метода. Следующее работает, но я чувствую, что должен быть лучший способ разрешения фабричного метода создания, см. GetMethodName и как он используется.
public class FooFactoryResolver : ISubDependencyResolver
{
private static string factoryMethodName;
private readonly IWindsorContainer container;
public FooFactoryResolver ( IWindsorContainer container )
{
this.container = container;
}
private static string GetMethodName()
{
if (factoryMethodName == null)
{
IFooFactory fooFactory = null;
Expression<Func<IFoo<object, object>>> expression =
() => fooFactory .CreateFoo<object, object>();
factoryMethodName = ( (MethodCallExpression)expression.Body ).
Method.Name;
}
return factoryMethodName;
}
public object Resolve(CreationContext context,
ISubDependencyResolver contextHandlerResolver,
Castle.Core.ComponentModel model, DependencyModel dependency)
{
return
TryToResolveDirectly( dependency ) ??
TryToResolveUsingFactories(dependency) ??
ComponentNotFound(dependency);
}
private static object ComponentNotFound(DependencyModel dependency)
{
throw new ComponentNotFoundException(dependency.TargetType);
}
private object TryToResolveUsingFactories(DependencyModel dependency)
{
var fooFactories = this.container.ResolveAll<IFooFactory>();
Type[] genericTypes = dependency.TargetItemType.
GetGenericArguments().ToArray();
return ( from fooFactory in fooFactories
where fooFactory.CanCreate( genericTypes[0],
genericTypes[1] )
let factoryMethod = fooFactory.GetType().
GetMethod( GetMethodName() )
select factoryMethod.MakeGenericMethod(
genericTypes.ToArray() ).
Invoke( fooFactory, new object[0] ) ).
FirstOrDefault();
}
private object TryToResolveDirectly(DependencyModel dependency)
{
return this.container.Kernel.HasComponent(dependency.TargetType) ?
this.container.Resolve( dependency.TargetType ) : null;
}
public bool CanResolve(CreationContext context,
ISubDependencyResolver contextHandlerResolver,
Castle.Core.ComponentModel model, DependencyModel dependency)
{
return dependency.TargetType.GetGenericTypeDefinition() ==
typeof( IFoo<,> );
}
}
public interface IFoo<T1, T2> { }
public interface IFooFactory
{
IFoo<T1, T2> CreateFoo<T1, T2>();
bool CanCreate(Type a, Type b);
}
Я не уверен, является ли это оскорблением или нет, но это делает работу, я просто чувствую, что упускаю что-то очевидное. Я надеялся, что будет какой-то способ изменить универсальные параметры в MethodInfo из MethodCallExpression или способ вернуться из MethodInfo в его 'Parent' и вызвать MakeGenericMethod для этого, используя типы, которые я хочу.