C# 简单注入器开放泛型装饰器

C# 简单注入器开放泛型装饰器,c#,.net,dependency-injection,ioc-container,simple-injector,C#,.net,Dependency Injection,Ioc Container,Simple Injector,我试图利用simple injector中的一些优秀功能 我目前和装饰师有问题,他们没有受到打击,当我期待他们太多 我是这样注册的: container.RegisterManyForOpenGeneric( 类型(ICommandHandler), AppDomain.CurrentDomain.GetAssemblys()); container.RegisterDecorator( 类型(ICommandHandler), 类型(CreateValidFriendlyUrlCommandH

我试图利用simple injector中的一些优秀功能

我目前和装饰师有问题,他们没有受到打击,当我期待他们太多

我是这样注册的:

container.RegisterManyForOpenGeneric(
类型(ICommandHandler),
AppDomain.CurrentDomain.GetAssemblys());
container.RegisterDecorator(
类型(ICommandHandler),
类型(CreateValidFriendlyUrlCommandHandler),
context=>context.ServiceType==typeof(ICommandHandler)
);
container.RegisterDecorator(
类型(ICommandHandler),
typeof(CreateProductValidationCommandHandler),
context=>context.ServiceType==typeof(ICommandHandler)
);
我想我一定遗漏了什么,因为我希望对
ICommandHandler
的调用在运行自身之前将调用
CreateValidFriendlyUrlCommandHandler
CreateProductValidationCommandHandler

我尝试过以下不同的注册方式:

container.RegisterManyForOpenGeneric(
类型(ICommandHandler),
AppDomain.CurrentDomain.GetAssemblys());
container.RegisterDecorator(
类型(ICommandHandler),
类型(CreateValidFriendlyUrlCommandHandler),
context=>context.ImplementationType==typeof(CreateProductCommandHandler)
);
container.RegisterDecorator(
类型(ICommandHandler),
typeof(CreateProductValidationCommandHandler),
context=>context.ImplementationType==typeof(CreateProductCommandHandler)
);
CreateProductValidationCommandHandler
CreateValidFriendlyUrlCommandHandler
实现
ICommandHandler
时,我认为在类型
ICommandHandler
上注册
ICommandHandler
的修饰符可能会遇到一些循环引用

但改变这一点没有什么区别

这是我的
CreateProductValidationCommandHandler

公共类CreateProductValidationCommandHandler
:ICommandHandler
{
私有只读ICommandHandler;
私有只读IValidationService validationService;
公共CreateProductValidationCommandHandler(
ICommandHandler,
IValidationService验证服务)
{
这是装饰过的;
this.validationService=validationService;
}
公共无效句柄(CreateProductCommand)
{
如果(!validationService.IsValidFriendlyName)(
command.Product.ProductFriendlyUrl)
{
command.ModelStateDictionary.AddModelError(
“ProductFriendlyUrl”,
“友好的产品名称无效…”);
返回;
}
如果(!validationService.IsUniqueFriendlyName(
command.Product.ProductFriendlyUrl)
{
command.ModelStateDictionary.AddModelError(
“ProductFriendlyUrl”,
“友好的产品名称是……”);
返回;
}
}
}
这是我的
CreateValidFriendlyUrlCommandHandler

公共类CreateValidFriendlyUrlCommandHandler
:ICommandHandler
{
私有只读ICommandHandler;
public CreateValidFriendlyUrlCommandHandler(ICommandHandler)
{
这是装饰过的;
}
公共无效句柄(CreateProductCommand)
{
if(string.IsNullOrWhiteSpace)(
command.Product.ProductFriendlyUrl)
{
command.Product.ProductFriendlyUrl=
MakeFriendlyUrl(command.Product.Name);
}
}
}

问题在于,Simple Injector将永远无法将
ICommandHandler
实现包装到您的一个装饰器中,因为存在无法解决的泛型类型
TCommand
。如果装饰程序的
句柄
方法调用
装饰的
实例,您就会注意到这一点。例如:

public class CreateValidFriendlyUrlCommandHandler<TCommand>
    : ICommandHandler<CreateProductCommand>
{
    private readonly ICommandHandler<TCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(
        ICommandHandler<TCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        // This won't compile since CreateProductCommand and
        // TCommand are not related.
        this.decorated.Handle(command);
    }
}
不过,简单的Injector无法“猜测”这个
t命令应该是
CreateProductCommand
,这就是为什么您的“decorator”没有包装好

长话短说:扔掉
t命令

public class CreateValidFriendlyUrlCommandHandler
    : ICommandHandler<CreateProductCommand>
{
    private ICommandHandler<CreateProductCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(
        ICommandHandler<CreateProductCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        // logic here
    }
}
公共类CreateValidFriendlyUrlCommandHandler
:ICommandHandler
{
私人ICommandHandler;
公共CreateValidFriendlyUrlCommandHandler(
ICommandHandler(已装饰)
{
这是装饰过的;
}
公共无效句柄(CreateProductCommand)
{
//这里的逻辑
}
}
或者使用类型约束使其成为泛型:

   public class CreateValidFriendlyUrlCommandHandler<TCommand>
        : ICommandHandler<TCommand>
        where TCommand : CreateProductCommand
    {
        private ICommandHandler<TCommand> decorated;

        public CreateValidFriendlyUrlCommandHandler(
            ICommandHandler<TCommand> decorated)
        {
            this.decorated = decorated;
        }

        public void Handle(TCommand command)
        {
            // logic here
        }
    }
公共类CreateValidFriendlyUrlCommandHandler
:ICommandHandler
其中TCommand:CreateProductCommand
{
私人ICommandHandler;
公共CreateValidFriendlyUrlCommandHandler(
ICommandHandler(已装饰)
{
这是装饰过的;
}
公共无效句柄(TCommand命令)
{
//这里的逻辑
}
}
或者删除类型约束并允许处理任何类型的命令,而不仅仅是
CreateProductCommand


请注意,如果要定义多个装饰器,而这些装饰器只能处理一种特定类型的命令处理程序,则可能需要重新考虑您的策略。您的设计可能有问题。

您的装饰程序不应是通用的。事实上,从技术上讲,它们不是装饰程序:-)请注意,
Appdomain.CurrentDomain.GeAssemblies
仅返回已加载的程序集。如果所有实现都与
ICommandHandler
位于同一个程序集中,则不会有问题,但要小心。好吧,这是有道理的,我所做的一些事情就是让它按我想要的方式工作。我有一个开放的通用注册,并希望一些装饰,但我只希望他们应用时,命令
public class CreateValidFriendlyUrlCommandHandler
    : ICommandHandler<CreateProductCommand>
{
    private ICommandHandler<CreateProductCommand> decorated;

    public CreateValidFriendlyUrlCommandHandler(
        ICommandHandler<CreateProductCommand> decorated)
    {
        this.decorated = decorated;
    }

    public void Handle(CreateProductCommand command)
    {
        // logic here
    }
}
   public class CreateValidFriendlyUrlCommandHandler<TCommand>
        : ICommandHandler<TCommand>
        where TCommand : CreateProductCommand
    {
        private ICommandHandler<TCommand> decorated;

        public CreateValidFriendlyUrlCommandHandler(
            ICommandHandler<TCommand> decorated)
        {
            this.decorated = decorated;
        }

        public void Handle(TCommand command)
        {
            // logic here
        }
    }