在 MEF 中,AssemblyCatalog
用于扫描程序集以查找所有导出类型并配置容器。有 Ninject 的等效项吗?
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
var container = new CompositionContainer(catalog);
最佳答案
在 Ninject 中,使用类型属性和扫描程序集来添加绑定(bind)的能力是由名为 Ninject.Extensions.Conventions 的扩展提供的。 .
添加约定包,例如使用包管理器控制台:
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
将类型绑定(bind)到给定接口(interface):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>());
}
}
关于c# - Ninject 相当于 MEF AssemblyCatalog,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27578361/