使用ninject,我可以创建一个绑定到具有属性并满足谓词的类吗?

时间:2016-09-06 07:15:19

标签: c# dependency-injection ninject

我有一个类的基类,可以作为中央系统的插件。我想允许在第三方程序集中定义这些插件。中央系统根据一些命令行参数实例化插件。

为实现这一目标,我创建了一个可以使用这些类进行修饰的属性,如:

[ArgName("some-module")]

在初始化时,我使用一段反映所有已加载类型的代码,尝试找到具有该属性和正确参数的代码:

AppDomain.CurrentDomain.GetAssemblies()
         .SelectMany(x => x.GetTypes())
         .SingleOrDefault(x => /* check for attribute and predicate */);

这很好用。

但我觉得我正在重新发明DI框架本身可能拥有的东西。所以,既然我已经在我的项目中使用Ninject来处理其他一些依赖项,我想知道:有没有办法可以将这个职责委托给Ninject,而不是编写自定义反射代码?

换句话说,Ninject是否已经有一些我错过的内容大致如下:

kernel.Bind<ModuleBase>()
      .ToTypesThatHaveThisAttribute<ArgName>()
      .With(x => x.Name == userProvidedCommandlineArgument);

当然,我知道我可以为BindingToSyntax<T>创建上述扩展方法,并在使用它时使语法更好。但是如果Ninject内置了这个功能,我想完全放弃反射代码。

1 个答案:

答案 0 :(得分:2)

使用Ninject.Extensions.Conventions你可以实现这样的目标(未经测试)。

string arg = null;
Kernel.Bind(x =>
{
    x.FromThisAssembly()
        .Select(t =>
        {
            var attributes = t.GetCustomAttributes(typeof(ArgNameAttribute));
            if (attributes.Length == 0) return false;
            var attribute = attributes[0];
            return attribute.ArgName == arg;
        })
        .BindSelection((type, interfaces) => new[] {typeof(PluginBase)});
});

但说实话,与手动类型选择和与Reflection的绑定相比,它的代码量几乎相同,类似于您所写的内容。我的意思是这样的。

AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(x => x.GetTypes())
    .Where(x => {
         var attributes = t.GetCustomAttributes(typeof(ArgNameAttribute));
         if (attributes.Length == 0) return false;
         var attribute = attributes[0];
         return attribute.ArgName == arg;
    })
    .Select(x => Kernel.Bind<PluginBase>().To(x))...

我可能会在没有Conventions扩展名的情况下执行此操作,除非您发现它在其他方面有用。

请注意,这些代码都没有经过测试,仅举例说明。