我能想到的有两种解决方案适用于您的场景。您可以手动创建InstanceProducer 实例并对其进行过滤以获取要执行的正确处理程序,或者您使用一些环境值并应用一个装饰器来决定是否执行此类处理程序。以下是两者的示例:
手动创建 InstanceProducers:
// During registration
var handlerProducerInfos = (
from type in container.GetTypesToRegister(typeof(IMessageHandler<>), assemblies)
let registration = Lifestyle.Transient.CreateRegistration(type, container)
from service in type.GetClosedInterfacesFor(typeof(IMessageHandler<>))
let producer = new InstanceProducer(service, registration)
select new
{
Producer = new InstanceProducer(service, registration),
Namespace = type.Namespace
})
.ToArray();
// During execution
Type handlerType = typeof(IMessageHandler<>).MakeGenericType(message.GetType());
var handlers =
from info in handlerProducerInfos
where handlerType == info.Producer.ServiceType
where info.Namespace == "Context1Namespace"
select info.Producer.GetInstance();
foreach (dynamic handler in handlers) {
}
使用环境值和特殊装饰器:
这里我们可以像往常一样使用CompositeMessageHandler<T>:
public class CompositeMessageHandler<T> : IMessageHandler<T> {
private readonly IEnumerable<IMessageHandler<T>> handlers;
public CompositeMessageHandler(IEnumerable<IMessageHandler<T>> handlers) {
this.handlers = handlers;
}
public void Handle(T message) {
foreach (var handler in this.handlers) {
handler.Handle(message);
}
}
}
我们有一个特殊的装饰器,它依赖于 Simple Injector 的 DecoratorContext 对象。 Simple Injector 可以将此类注入到您的装饰器中,并为您的装饰器提供有关其运行的上下文的更多信息:
public class ContextualMessageHandlerDecorator<T> : IMessageHandler<T> {
private readonly DecoratorContext context;
private readonly IMessageHandler<T> decoratee;
public ContextualMessageHandlerDecorator(DecoratorContext context,
IMessageHandler<T> decoratee) {
this.context = context;
this.decoratee = decoratee;
}
public static string ContextNamespace { get; set; }
public void Handle(T message) {
// Here we get the ambient value from the ContextHelper and match it
// with the namespace of the real message handler
if (ContextHelper.ContextNamespace.Value.Equals(
this.context.ImplementationType.Namespace)) {
this.decoratee.Handle(message);
}
}
}
public static ContextHelper {
public static readonly ThreadLocal<string> ContextNamespace =new ThreadLocal<string>();
}
我们可以按如下方式注册所有内容:
// Register the concrete message handlers as collection
container.RegisterCollection(typeof(IMessageHandler<>), assemblies);
// Register the composite to wrap the real message handlers
container.Register(typeof(IMessageHandler<>), typeof(CompositeMessageHandler<>));
// Register your decorators here:
// Register our 'contextual' decorator last, but prevent it to be wrapped
// around the CompositeMessageHandler.
container.RegisterDecorator(typeof(IMessageHandler<>),
typeof(ContextualMessageHandlerDecorator<>),
c => !c.ImplementationType.Name.StartsWith("CompositeMessageHandler"));
执行期间:
Type handlerType = typeof(IMessageHandler<>).MakeGenericType(message.GetType());
// Resolves the composite handler, wrapping all handlers for T.
dynamic handler = _container.GetInstance(handlerType);
// Set the context to allow filtering on namespace
ContextHelper.ContextNamespace.Value = "Context1Namespace";
// handle the message
handler.Handle((dynamic)message);