Ninject等效于MEF AssemblyCatalog [英] Ninject equivalent to MEF AssemblyCatalog

查看:74
本文介绍了Ninject等效于MEF AssemblyCatalog的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在MEF中,AssemblyCatalog用于扫描部件中的所有导出类型并配置容器. Ninject有等效功能吗?

In MEF, an AssemblyCatalog is used to scan an assembly for all exported types and configure the container. Is there an equivalent with Ninject?

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

推荐答案

在Ninject中,名为

In Ninject, the ability to use attributes on types and scan assemblies to add bindings is provided by an extension named Ninject.Extensions.Conventions.

  1. 添加约定包,例如使用Package Manager控制台:

  1. Add the conventions package, e.g. using the Package Manager Console:

Install-Package Ninject.Extensions.Conventions

  • 创建一些自定义属性以用于您的服务.这相当于MEF中的ExportAttribute:

  • Create some custom attribute to use on your services. This will be the equivalent to the ExportAttribute in MEF:

    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将类型绑定到给定的接口:

  • Create a custom BindingGenerator that uses our ExportAttribute to bind a type to the given 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();
            }
        }
    }
    

  • 创建扩展方法以在内核上使用并添加约定:

  • Create an extension method to use on the kernel and add the convention:

    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>());
        }
    }
    

  • 现在,对于如此常见的事情,这似乎需要大量工作,但是它非常灵活且可扩展.它可以完成您想要执行的任何操作.将其放在实用程序类库中,并在需要的地方使用它,像这样:

    Now this seems like a lot of work for something so common, but it's very flexible and extensible. It does whatever you want it to do. Put it in a utilities class library and use it wherever you want like this:

    [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>());
        }
    }
    

    这篇关于Ninject等效于MEF AssemblyCatalog的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆