Ninject equivalent to MEF AssemblyCatalog
本文关键字:AssemblyCatalog MEF to equivalent Ninject | 更新日期: 2023-09-27 18:34:50
在 MEF 中,AssemblyCatalog
用于扫描程序集以查找所有导出的类型并配置容器。有与Ninject等价物吗?
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
var container = new CompositionContainer(catalog);
在 Ninject 中,使用类型和扫描程序集的属性来添加绑定的功能由名为 Ninject.Extensions.Convention 的扩展提供。
-
添加约定包,例如使用包管理器控制台:
Install-Package Ninject.Extensions.Conventions
-
创建一些要在服务上使用的自定义属性。这将等效于 MEF 中的
ExportAttribute
:public enum ExportScope { Singleton, Transient } [AttributeUsage(AttributeTargets.Class)] public class ExportAttribute : Attribute { public ExportAttribute(Type serviceInterface, ExportScope scope = ExportScope.Singleton) { this.ServiceInterface = serviceInterface; this.Scope = scope; } public Type ServiceInterface { get; set; } public ExportScope Scope { get; set; } }
-
创建一个自定义 BindingGenerator,它使用我们的
ExportAttribute
将类型绑定到给定接口:public class ExportAttributeBindingGenerator : IBindingGenerator { public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot) { var attribute = type.GetCustomAttribute<ExportAttribute>(); var serviceType = attribute.ServiceInterface; if (!serviceType.IsAssignableFrom(type)) { throw new Exception(string.Format("Error in ExportAttribute: Cannot bind type '{0}' to type '{1}'.", serviceType, type)); } var binding = bindingRoot.Bind(serviceType).To(type); switch (attribute.Scope) { case ExportScope.Singleton: yield return (IBindingWhenInNamedWithOrOnSyntax<object>) binding.InSingletonScope(); break; case ExportScope.Transient: yield return (IBindingWhenInNamedWithOrOnSyntax<object>) binding.InTransientScope(); break; default: throw new ArgumentOutOfRangeException(); } } }
-
创建要在内核上使用的扩展方法并添加约定:
public static class NinjectBindingExtensions { public static void BindExportsInAssembly(this IBindingRoot root, Assembly assembly) { root.Bind(c => c.From(assembly) .IncludingNonePublicTypes() .SelectAllClasses() .WithAttribute<ExportAttribute>() .BindWith<ExportAttributeBindingGenerator>()); } }
现在,对于如此常见的事情来说,这似乎需要做很多工作,但它非常灵活和可扩展。它做任何你想让它做的事情。把它放在实用程序类库中,并在任何你想要的地方使用它,就像这样:
[Export(typeof(IFoo))]
public class Foo : IFoo
{
}
[Export(typeof(IBar), ExportScope.Transient)]
public class Bar : IBar
{
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestNinjectConventions()
{
var kernel = new StandardKernel();
kernel.BindExportsInAssembly(typeof(IFoo).Assembly);
kernel.Get<IFoo>().Should().Be(kernel.Get<IFoo>());
kernel.Get<IBar>().Should().NotBe(kernel.Get<IBar>());
}
}