在MEF中,AssemblyCatalog
用于扫描所有导出类型的程序集并配置容器。是否与Ninject等效?
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
var container = new CompositionContainer(catalog);
答案 0 :(得分:4)
在Ninject中,使用类型和扫描程序集上的属性来添加绑定的功能由名为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
将类型绑定到给定的接口:
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>());
}
}