代码之家  ›  专栏  ›  技术社区  ›  Martin Wedvich

简单注入器装饰器和协方差

  •  1
  • Martin Wedvich  · 技术社区  · 8 年前

    我有一个应用程序,其中我的 DbContext 实施。为了在消费类中支持这一点,我创建了一个 IDbContextProvider 与a的接口 Get 方法可以为我提供 数据库上下文 我需要的实例。

    我还有一个 ICommandHandler 事情进展顺利,我正在尝试创建一个装饰器,它将调用 DbContext.SaveChangesAsync() 成功执行命令时。我这样注册我的装饰师:

    container.RegisterDecorator(typeof(ICommandHandler<>),
        typeof(SaveChangesCommandHandlerDecorator<>));
    

    数据库上下文 实现,我知道所有派生自 数据库上下文 有一个 SaveChangesAsync() 方法,我想我可以使用协方差。我的界面如下所示:

    public public interface IDbContextProvider<out TDbContext> where TDbContext : DbContext
    {
        TDbContext Get(DbPrivileges privileges);
    }
    

    我的装饰师的相关部分:

    public class SaveChangesCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand> 
        where TCommand : ICommand
    {
        private readonly ICommandHandler<TCommand> _handler;
        private readonly IDbContextProvider<DbContext> _dbContextProvider;
    
        public SaveChangesCommandHandlerDecorator(
            ICommandHandler<TCommand> handler, IDbContextProvider<DbContext> dbContextProvider)
        {
            _handler = handler;
            _dbContextProvider = dbContextProvider;
        }
    
        ...
    

    然而,当我打电话时 Verify() 在我的容器上,它抱怨 IDbContextProvider 无效,因为它正在寻找“基” IDbContextProvider<DbContext> 而不是在我的应用程序中注册的一个。

    savechangescommandhandlerdecotor类型的构造函数<CreateUserCommand>包含名为“dbContextProvider”且类型为IDbContextProvider的参数<DbContext>未注册。请确保IDbContextProvider<DbContext>已注册,或更改SaveChangesCommand和HandlerDecorator的构造函数<CreateUserCommand>。请注意,存在不同类型的注册(已编辑)。IDbContextProvider<TDbContext>而请求的类型是(编辑的)。IDbContextProvider<微软EntityFrameworkCore。DbContext>。

    这实际上是有道理的,因为简单的注入器无法知道要将什么样的混凝土类型注入到 dbContextProvider 参数

    有没有办法自定义我的装饰器的创建方式,以便它可以查看底层的依赖关系 ICommandHandler 实现的依赖项,并选择 IDbContextProvider 创作时的签名?如果我的命令处理程序有一个 IDbContextProvider<AwesomeDbContext>

    1 回复  |  直到 8 年前
        1
  •  2
  •   Steven    8 年前

    让我澄清一下:您的应用程序包含多个 DbContext 实施,例如:

    • AwesomeDbContext
    • 事件BetterDBContext
    • BrilliantDbContext

    现在,每个命令处理程序通常取决于一个特定的 通过获得 IDbContextProvider<TDbContext> 其中 TDbContext 是具体的 数据库上下文 实施

    现在,根据decorator命令处理程序所依赖的内容,您希望注入完全相同的内容 IDbContextProvider<TDbContext> 也可以在decorator中实现,因此可以保存对该特定实例的更改。

    如果我正确地总结了你的问题,你问题的简短答案是:不,你不能那样做。

    更长的答案是,是的,这实际上可以通过为 TDB上下文 给你的 SaveChangesCommandHandlerDecorator<TCommand, TDbContext> 装饰器,并使用 RegisterDecorator 接受 Func<DecoratorPredicateContext, Type> . 使用提供的 DecoratorPredicateContext 对于factory代理,您可以分析其 Expression 属性来确定 IDbContextProvider<TDbContext> 注入,并基于该信息构建的 SaveChangesCommand和HandlerDecorator<t命令,TDbContext> 您填写的位置 但是离开 TCommand 打开以供简单喷油器加注。

    但老实说,我不会走这条路。这需要大量的工作,导致代码难以理解,你的同事会因此讨厌你。

    相反,尝试注入 IDbContextProvider<TDbContext> 而不是将实例放入装饰器。你可以通过制作 IDbContextProvider<out TDbContext> 单独注册,并作为集合的一部分使用 RegisterCollection .

    当您注入集合时,装饰器只需在所有 数据库上下文 实例。 SaveChanges