c# - Ninject 相当于 MEF AssemblyCatalog

标签 c# .net dependency-injection ninject mef

在 MEF 中,AssemblyCatalog 用于扫描程序集以查找所有导出类型并配置容器。有 Ninject 的等效项吗?

var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
var container = new CompositionContainer(catalog);

最佳答案

在 Ninject 中,使用类型属性和扫描程序集来添加绑定(bind)的能力是由名为 Ninject.Extensions.Conventions 的扩展提供的。 .

  1. 添加约定包,例如使用包管理器控制台:

    Install-Package Ninject.Extensions.Conventions
    
  2. 创建一些自定义属性以用于您的服务。这将等效于 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; }
    }
    
  3. 创建自定义 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();
            }
        }
    }
    
  4. 创建一个扩展方法以在内核上使用并添加约定:

    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/

相关文章:

.NET 抽象类

javascript - 我的 Angular 应用程序中的依赖注入(inject)在哪里出了问题

c# - Autofac 依赖注入(inject)在 Debug 中有效,但在 Release 中崩溃

c# - ASP.NET 用户控件 : check if usercontrol is visible

c# - 获取大于 24 小时的日期差异

java - 一切的存储过程

c# - 如何使用 C# 为 OpenSTV 选举生成 .BLT 文件?

java - Guice - 使用两种不同的实现注入(inject)对象

c# - 拦截 C# webbrowser 的超链接

c# - Python 中不安全的图像处理,如 C# 中的 LockBits