C# 如何在Simple Injector中注册具有复杂类型约束的开放泛型类型?

C# 如何在Simple Injector中注册具有复杂类型约束的开放泛型类型?,c#,dependency-injection,inversion-of-control,simple-injector,C#,Dependency Injection,Inversion Of Control,Simple Injector,我有一个打开的泛型类型AccessMessageHandler,每次解析IProcessHandler时都要解析它。我该怎么做 这是我的代码: 公共接口IProcess{} 公共接口IProcessHandler,其中TProcess:IProcess{ 无效句柄(TProcess消息); } 公共类AccessMessage:IProcess,其中TProcess:IProcess{ 公共虚拟字符串用户名{get;protected set;} 公共虚拟TProcess InnerProces

我有一个打开的泛型类型
AccessMessageHandler
,每次解析
IProcessHandler
时都要解析它。我该怎么做

这是我的代码:

公共接口IProcess{}
公共接口IProcessHandler,其中TProcess:IProcess{
无效句柄(TProcess消息);
}
公共类AccessMessage:IProcess,其中TProcess:IProcess{
公共虚拟字符串用户名{get;protected set;}
公共虚拟TProcess InnerProcess{get;protected set;}
}
公共类AccessMessageHandler:IPProcessHandler
其中TProcess:IProcess{
public AccessMessageHandler(IProcessHandler innerHandler){}
公共无效句柄(AccessMessage){
//访问控制
_Handle(message.InnerProcess)
}
}
公共类JustDoIt:IProcess{
公共虚拟字符串What{get;set;}
}
公共类JustDoItHandler:IProcessHandler{
公共无效句柄(JustDoIt消息){
//处理
}
}
如何注册IProcessHandler、AccessMessageHandler以进行如下简单解决:

var accessMessageProcess=new AccessMessage()
{ 
Username=“user”,
InnerProcess=new JustDoIt(){What=“xxx”}
};
var handler=GetHandlerFor(accessMessageProcess);
//必须返回AccessMessageHandler(JustDoItHandler)
handler.Handle(accessMessageProcess);

您可以进行以下注册:

container.RegisterManyForOpenGeneric(
    typeof(IProcessHandler<>), 
    typeof(JustDoItHandler).Assembly);

container.RegisterOpenGeneric(
    typeof(IProcessHandler<>), 
    typeof(AccessMessageHandler<>));
container.RegisterDecorator(typeof(IProcessHandler<>), 
    typeof(AccessProcessHandlerDecorator<>));
这将解析以下图表:

IProcessHandler<AccessMessage<JustDoIt>> handler = 
    new AccessMessageHandler<JustDoIt>(
        new JustDoItHandler());
IProcessHandler=
新的AccessMessageHandler(
新的JustDoItHandler());

但请注意,
AccessMessageHandler
不是装饰程序。装饰器包装与它实现的类型相同,但是您的
AccessMessageHandler
实现
IProcessHandler
但包装
IProcessHandler
。我认为这个模式的正确名称是代理。

如果当前用户的信息是您希望传递的唯一信息,那么您最好将此用户信息隐藏在抽象后面。通过这种方式,您可能可以防止消费者需要使用特定的
IProcessHandler
接口,并且可以避免必须从每个消费者那里传递用户名(这是可以忘记的额外代码,也是要进行单元测试的额外代码)

如果将此信息隐藏在抽象后面,则可以避免将
IProcessHandler
接口扩展为
IProcessHandler
接口,从而允许您使用装饰器:

public class AccessProcessHandlerDecorator<TProcess> : IProcessHandler<TProcess> {
    private readonly IProcessHandler<TProcess> decoratee;
    private readonly IPrincipal userContext;

    public AccessProcessHandlerDecorator(IProcessHandler<TProcess> decoratee,
        IPrincipal userContext) {
        this.decoratee = decoratee;
        this.userContext = userContext;
    }

    public void Handle(TProcess process) {
        string user = this.userContext.Identity.Name;

        // access control

        this.decoratee.Handle(process);
    }
}
可以按如下方式注册
AccessProcessHandlerDecorator

container.Register<IPrincipal>(() => Thread.CurrentPrincipal);
container.RegisterDecorator(typeof(IProcessHandler<>), 
    typeof(AccessProcessHandlerDecorator<>));
进行以下注册时:

container.RegisterManyForOpenGeneric(
    typeof(IProcessHandler<>), 
    typeof(JustDoItHandler).Assembly);

container.RegisterOpenGeneric(
    typeof(IProcessHandler<>), 
    typeof(AccessMessageHandler<>));
container.RegisterDecorator(typeof(IProcessHandler<>), 
    typeof(AccessProcessHandlerDecorator<>));
container.RegisterDecorator(typeof(IProcessHandler),
类型(AccessProcessHandlerDecorator));

AccessProcessHandlerDecorator
将仅应用于任何
IProcessHandler
而不应用于任何其他对象。

此解决方案非常完美,但当AccessProcessHandlerDecorator像您的定义一样使用时,它将对所有IProcess-IProcessHandler进行访问控制。如果是AccessMessage,我需要在AccessProcessHandler中处理IProcess。@oguzh4n在注册decorator
容器时,可以通过指定一个
谓词来精确控制修饰的内容。RegisterDecorator(typeof(IProcessHandler)、typeof(AccessProcessHandlerDecorator)、c=>{var inner=c.ServiceType.GetGenericArguments()[0];if(inner.IsGenericType){return inner.GetGenericTypeDefinition()==typeof(AccessMessage);}return false;})我被误解了,AccessProcessHandlerDecorator必须只处理AccessMessage消息,AccessProcessHandlerDecorator内部处理程序必须是IPProcessHandler(任何处理程序)@oguzh4n,我不确定我是否明白你的意思。有什么我可以澄清的吗?或者你的回答只是一个评论?
container.RegisterDecorator(typeof(IProcessHandler<>), 
    typeof(AccessProcessHandlerDecorator<>));