Windsor Generic Typed Factory
I'm trying to convert a factory class that get's a message of a certain type and resolves the processors for that message type to an implementation the Typed Factory Facility.
The code I'm starting from is this:
public interface IProcessor<in T> where T : Message
{
void Process(T message);
}
public class ProcessorFactory : IProcessorFactory
{
private readonly IKernel _container;
public ProcessorFactory(IKernel container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public void Process(Message message)
{
// Create a specific message processor type
var processorType = typeof(IProcessor<>).MakeGenericType(message.GetType());
// Resolve all processors for that message
var processors = _container.ResolveAll(processorType);
foreach (var processor i开发者_JAVA百科n processors)
{
processor.GetType().GetMethod("Process").Invoke(processor, new[] { message });
}
}
public class ProcessorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IProcessorFactory>().ImplementedBy<ProcessorFactory>(),
AllTypes.FromThisAssembly().BasedOn(typeof(IProcessor<>)).WithService.FirstInterface().
AllowMultipleMatches());
}
}
Based on the following blogpost and documentation from Castle Windsor I created the following:
public interface IProcessor
{
void Process();
}
public interface IProcessor<T> where T : Message
{
/// <summary>
/// Message to process
/// </summary>
T Message { get; set; }
}
public interface IProcessorFactory
{
IProcessor[] GetAllProcessorsForMessage(Message message);
}
public class ProcessorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>()
.Register(
Component.For<ProcessorSelector, ITypedFactoryComponentSelector>(),
Component.For<AutoReleaseProcessorInterceptor>(),
AllTypes.FromThisAssembly()
.BasedOn(typeof(IProcessor<>))
.WithService.Base()
.Configure(c => c.LifeStyle.Is(LifestyleType.Transient)
.Interceptors<AutoReleaseProcessorInterceptor>()),
Component.For<IProcessorFactory>().AsFactory(f => f.SelectedWith<ProcessorSelector>()));
}
}
public class ProcessorSelector : DefaultTypedFactoryComponentSelector
{
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
return typeof(IProcessor<>).MakeGenericType(arguments[0].GetType());
}
}
When I call factory.GetAllProcessorsForMessage(new ExampleMessage())
I get the following error:
Unable to cast object of type 'Castle.Proxies.IProcessor`1Proxy' to type 'MyNamespace.Processors.IProcessor[]'.
What am I doing wrong and how can the code be improved?
That's simple. As the exception message is saying your proxies do not implement the non generic IProcessor
interface. You need to make it a service on those components too.
Also your selector tells Windsor what you're after is a single item whereas the signature implies you want a collection. Hence the cast fails because you're casting a single item to an array type.
So your selector's method should have
.MakeArrayType()
at the end.
精彩评论