Ninject 的 Bind.ToMethod 使用 CQRS 的等价单位

Unity equivalent for Ninject's Bind.ToMethod Using CQRS

我正在关注这个 CQS 教程 https://github.com/Code-First/CQS-Sample,它使用 Ninject。

我目前正在使用 Unity 并尝试转换它:

    Bind<IQueryFactory>().ToMethod(t => new QueryFactory(x => Container.Current.Resolve(x))).InTransientScope();

我的查询工厂如下图:

public class QueryFactory : IQueryFactory
{
    private readonly Func<Type, object> _resolveCallback;

    public QueryFactory(Func<Type, object> resolveCallback)
    {
        _resolveCallback = resolveCallback;
    }

    public T ResolveQuery<T>()
        where T : class, IQuery
    {
        return _resolveCallback(typeof (T)) as T;
    }
}

我试过container.RegisterType<IQueryFactory>(t => new InjectionFactory(u => u.Resolve(u)));,但没用。

您可能认为 InjectionFactory 是正确的选择。这编译:

container.RegisterType<IQueryFactory>(new ContainerControlledLifetimeManager(),
    new InjectionFactory((c, x, o) => new QueryFactory(t => c.Resolve(x))));

问题是类型 x 始终是 IQueryFactory,因此无法获得您想要的结果,即 return IQuery。

不幸的是,我认为当前的设计不太适合 Unity。

但是,通过一些细微的修改,您可以使工厂正常工作。有几种不同的方法可以做到这一点(例如,您可以在工厂中注入容器并从那里解析)但是在这个例子中我将使用字典。

首先我们修改工厂定义:

public class QueryFactory : IQueryFactory
{
    private readonly IDictionary<Type, Func<IQuery>> _factoryQueries;

    public QueryFactory(IDictionary<Type, Func<IQuery>> factoryQueries)
    {
        this._factoryQueries = factoryQueries;
    }

    public T ResolveQuery<T>() where T : class, IQuery
    {
        return this._factoryQueries[typeof(T)]() as T;
    }

基本上,Func<Type, object> resolveCallback 被交换为包含用于创建所有支持的 IQuery 类型的函数的 IDictionary。

接下来注册 IDictionary 和 IQueryFactory:

IUnityContainer container = new UnityContainer();

// Register all IQuery's
container.RegisterType<IActiveUsersQuery, ActiveUsersQuery>();
container.RegisterType<IUserByEmailQuery, UserByEmailQuery>();

IDictionary<Type, Func<IQuery>> factoryQueries = new Dictionary<Type, Func<IQuery>>()
{
    { typeof(IActiveUsersQuery), () => container.Resolve<IActiveUsersQuery>() },
    { typeof(IUserByEmailQuery), () => container.Resolve<IUserByEmailQuery>() },
};

// Register mapping
container.RegisterInstance<IDictionary<Type, Func<IQuery>>>(factoryQueries);
container.RegisterType<IQueryFactory, QueryFactory>();

var factory = container.Resolve<IQueryFactory>();

factory.ResolveQuery<IActiveUsersQuery>().Execute();
factory.ResolveQuery<IActiveUsersQuery>().Execute();

如前所述,一种依赖于容器的更简单的 QueryFactory 方法是:

public class QueryFactory : IQueryFactory
{
    private readonly IUnityContainer container;

    public QueryFactory(IUnityContainer container)
    {
        this.container = container;
    }

    public T ResolveQuery<T>()
        where T : class, IQuery
    {
        return this.container.Resolve(typeof(T)) as T;
    }
}

但是,有些人反对让工厂依赖于容器实现。

另一种方法是摆脱工厂方法并直接注入查询;这将使依赖关系变得明显,但我可以看到您希望根据命令类型动态获取查询的场景。此外,我还看到了命令和查询之间的关系,这些关系可以用组合根中解析的开放泛型来处理。