将工厂接口绑定到工厂,但具有实现的接口除外?

时间:2014-09-10 19:11:06

标签: c# dependency-injection ninject factory-pattern

我有一些工厂接口。

  • ICustomerManagementPresenterFactory
  • ICustomerDetailPresenterFactory

有些工厂不需要任何实现者,所以我可以按如下方式绑定它们。

IKernel kernel = new StandardKernel();
kernel.Bind(services => services
    .From(AppDomain.CurrentDomain
        .GetAssemblies()
        .Where(a => a.FullName.Contains("MyProject")
                 && !a.FullName.Contains("Tests")))
    .SelectAllInterfaces()
    .EndwingWith("Factory")
    .BindToFactory());

只要我不需要为构造函数提供参数,哪个应该通过Method Injection提供,哪个工作完美无瑕。

此外,使用此代码,我也绑定了ICustomerManagementPresenterFactory,并且它不受其实现者的约束。

ICustomerManagementPresenterFactory

public interface ICustomerManagementPresenterFactory { 
    CustomerManagementPresenter Create();
}

CustomerManagementPresenterFactory

public class CustomerManagementPresenterFactory : ICustomerManagementPresenterFactory {
    public CustomerManagementPresenterFactory(ICustomerManagementView view
                                            , ICustomerDetailPresenterFactory factory) {
        this.factory = factory; 
        this.view = view;
    }

    public CustomerManagementPresenter Create() {
        return new CustomerManagementPresenter(view, factory);
    }

    private readonly ICustomerDetailPresenterfactory factory;
    private readonly ICustomerManagementView view;
}

所以,因为 CustomerManagementPresenter 的构造函数有两个参数,我希望实现一个工厂,它不需要为它创建的类的依赖项注入方法,并且我继续使用{{ 3}}

所以,我想从Constructor Injection中受益,并且仍然以不同的方式绑定两者。

我怎么能这样做?

1 个答案:

答案 0 :(得分:1)

可悲的是,您无法检索类型列表"已选择"按惯例。 这意味着你必须在某种程度上解决它。

语法提供Where(Func<Type, bool> selector)Excluding(IEnumerable<Type> types)方法。因此,在将接口工厂与.ToFactory()绑定之前,您需要获取所有已实现工厂的接口。例如:

IKernel kernel = new StandardKernel();

IList<Type> implementedFactoryInterfaces = new List<Type>();
kernel.Bind(services => services
    .From(AppDomain.CurrentDomain
        .GetAssemblies()
        .Where(a => a.FullName.Contains("MyProject")
                    && !a.FullName.Contains("Tests")))
    .SelectAllClasses()
    .EndingWith("Factory")
    .Where(classFactoryType =>
    {
        implementedFactoryInterfaces.Add(classFactoryType.GetInterfaces().Single());
        return true;
    })
    .BindDefaultInterface());


kernel.Bind(services => services
    .From(AppDomain.CurrentDomain
        .GetAssemblies()
        .Where(a => a.FullName.Contains("MyProject")
                    && !a.FullName.Contains("Tests")))
    .SelectAllInterfaces()
    .EndingWith("Factory")
    .Excluding(implementedFactoryInterfaces)
    .BindToFactory());

另一种方法是实现一个绑定生成器,检查是否有传递接口的实现 - Type并相应地创建绑定:

public class InterfaceAndClassFactoryBindingGenerator : IBindingGenerator
{
    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
    {
        if (!type.IsInterface)
        {
            throw new ArgumentOutOfRangeException("type", type, "is not an interface, but only interfaces are supported");
        }

        Type classImplementingTheFactoryInterface = type.Assembly.GetTypes()
            .Where(t => t.IsClass)
            .SingleOrDefault(type.IsAssignableFrom);

        if (classImplementingTheFactoryInterface == null)
        {
            bindingRoot.Bind(type).ToFactory();
        }
        else
        {
            bindingRoot.Bind(type).To(classImplementingTheFactoryInterface);
        }
    }
}


IKernel kernel = new StandardKernel();
kernel.Bind(services => services
    .From(AppDomain.CurrentDomain
        .GetAssemblies()
        .Where(a => a.FullName.Contains("MyProject")
                    && !a.FullName.Contains("Tests")))
    .SelectAllInterfaces()
    .EndingWith("Factory")
    .BindWith<InterfaceAndClassFactoryBindingGenerator>());