首页 文章

如何根据工厂参数 - >命名空间路径获取ninject绑定?

提问于
浏览
1

我正在使用Ninject 3.0.1.10和来自NuGet的ninject.extensions.factory 3.0.1.0 - 在“真实”场景中我将使用ninject.extensions.conventions(而不是手动绑定IFoo),但我想保持这一点,试图简化问题 .

我有一个IFoo接口和它的多个实现,每个都在子命名空间和子文件夹下,名为Gen1和Gen2 . 我有一个IFooFactory接口,其意图是它根据指定的参数(字符串,枚举,等等)返回一个IFoo .

我在这个例子中使用枚举只是为了尝试使其更清晰 - 我最初创建了一个字符串版本,但感觉就像传递更多任意参数(例如字符串)的异议只会混淆问题 .

public enum ImplementationGeneration
{
    Gen1,
    Gen2,
    Gen3,
}

public interface IFoo
{
    void DoStuff();
}

public interface IFooFactory
{
    IFoo CreateFoo(ImplementationGeneration implementationGeneration);
}


namespace SomeRootNamespace.Gen1
{
    public class Foo : IFoo
    {
        public void DoStuff()
        {
            Console.WriteLine("Doing Type1 stuff");
        }
    }
}

namespace SomeRootNamespace.Gen2
{
    public class Foo : IFoo
    {
        public void DoStuff()
        {
            Console.WriteLine("Doing Type2 stuff");
        }
    }
}

现在,我理解让消费者'选择'这样的实现是一种理想情况下不存在的耦合形式,但恕我直言,它与Ninject已经支持的命名绑定具有相同的耦合级别 . 我想避免将属性添加到实现中,并且在工厂界面中使用GetGen1 / GetGen2 / etc方法是非常适合的,因为我最终通过某个开关违反OCP以将输入映射到要调用的方法(或手动使用反射)

我现在所拥有的完整/工作代码,如果可能的话,我宁愿避免使用:https://gist.github.com/4549677

它使用两种方法:

  • 一个手动工厂实现,违反了OCP并且传递了枚举的枚举

  • 使用带有IInstanceProvider实例的工厂扩展(子类StandardInstanceProvider来覆盖GetInstance) .

第二种方法似乎可以“接近”'正确的方式'来实现这一点,但是1)它保留了对内核的引用以便完成它的工作,这可能是一个坏主意,2)因为在调用期间搜索所有IFoo绑定时,我无法在IFoo的绑定中找到具体类型,它当前执行GetAll,因此它实例化N-1个实例,而不是此场景需要的实例 .

1 回答

  • 1

    好吧,我发现的东西至少比我上面的东西好 .

    它毕竟使用命名绑定,_1496119用于根据命名空间的最后部分命名所有绑定 . 这最终会将名称附加到许多绑定中,这些绑定不会导致其使用中出现任何问题(至少在我的测试中) .

    如果由于某种原因对于将来遇到这种问题的人来说是一个问题,你可以在通过约定设置绑定的代码中更加具体 - 例如,如果最后一个命名空间部分位于特定设置或匹配特定模式 .

    kernel.Bind(x => x
        .FromThisAssembly()
        .SelectAllClasses()
        .BindAllInterfaces()
        .Configure((binding, concreteType) =>
        {
            var concreteNamespace = concreteType.Namespace ?? String.Empty;
            var lastNamespacePart = concreteNamespace.Split('.').Last();
            binding.Named(lastNamespacePart);
        })
    );
    

    然后使用the UseFirstArgumentAsNameInstanceProvider根据工厂方法的第一个参数查找绑定名称(因此您不必与链接的Wiki页面相同) .

    public class UseFirstArgumentAsNameInstanceProvider : StandardInstanceProvider
    {
        protected override string GetName(System.Reflection.MethodInfo methodInfo, object[] arguments)
        {
            return arguments[0].ToString();
        }
    
        protected override ConstructorArgument[] GetConstructorArguments(System.Reflection.MethodInfo methodInfo, object[] arguments)
        {
            return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
        }
    }
    

    我有一个不同的/更好的选择,但至少这似乎是合理的,并没有任何明显的问题 . :)

相关问题