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

本文关键字:一个 属性 满足 谓词 我可以 ninject 使用 绑定 创建 | 更新日期: 2023-09-27 18:06:01

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

为了实现这一点,我创建了一个属性,这些类可以用它来装饰,类似于:
[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内置了这个功能,我想完全消除反射代码。

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

使用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)});
});

但说实话,与手动类型选择和反射绑定相比,这几乎是相同数量的代码,类似于您编写的代码。我的意思是这样的。

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扩展,除非你发现它在其他方面很有用。

请注意,这两个代码都没有经过测试,我只添加了它们,例如