【问题标题】:Using MEF with dependency injection将 MEF 与依赖注入一起使用
【发布时间】:2016-11-01 22:43:12
【问题描述】:

我有一个类,它使用像这样的记录器类型的依赖注入来实例化:

var _logger = Logger.GetLogger(LoggerType.MongoLogger);         
var service = new MyService(_logger);

在我的单元测试中,我替换了要使用的记录器:

var _logger = Logger.GetLogger(LoggerType.TextFileLogger);         

现在,我想使用 MEF 将 MyService 作为插件加载,我创建了这样的服务:

[Export(typeof(IService))]
    public class MyService: IService
    {
        private ILogger _logger;    

        public MyService(ILogger  logger)
        {
            this._logger = logger;
        }
        public void DoServiceWork()
        {
            _logger.Log("Starting service work");
        }
    }

如何使这个东西在 MEF 框架中工作?

【问题讨论】:

    标签: c# mef


    【解决方案1】:

    编辑: 添加了更详细的示例,使用控制台应用程序。

    引导类

    此类创建 MEF 容器并初始化聚合目录。您还应该实例化其他可导出项目,例如ILogger,由程序中的其他依赖类使用。创建属性并用Export 标记它们允许在整个程序中使用这些实例。

    你应该只实例化这个类一次。在这个例子中,我们在启动时在主程序块中实例化它。

    我们已将 ContainerILogger 标记为导出,因为我们希望这些实例可供其他依赖类使用。

    导出 IService

    使用 Export(IService) 标记您的 MySerivce 类允许它在 MEF 中导出。我们使用 MEF 通过调用Container.GetExportedValue<IService>(); 来获取它的一个实例。注意:默认情况下,MEF 将使用单例共享实例,即对象将被创建一次。如果您想要非共享实例,则必须使用 PartCreationPolicy(CreationPolicy.NonShared) 标记类

    using System.ComponentModel.Composition.Hosting;
    using System.ComponentModel.Composition;
    
    class Program
    {
        static void Main(string[] args)
        {
            var bootstrap = new Bootstrap();
            var service = bootstrap.Container.GetExportedValue<IService>();
            service.DoServiceWork();
        }
    
    
    }
    
    public class Bootstrap
    {
        [Export]
        public CompositionContainer Container { get; private set; }
    
        [Export(typeof(ILogger))]
        public ILogger Logger { get; private set; }
    
        public  Bootstrap()
        {
            //Create an aggregate catalog that will hold assembly references
            var catalog = new AggregateCatalog();
    
            //Adds this assembly. 
            //Exports defined in the classes and types within this assembly will now be composable
            //Add to the catalogs if there are more assemblies where exports are defined.
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
    
            //Create the CompositionContainer with the parts in the catalog
            this.Container = new CompositionContainer(catalog);
    
            this.Logger = Logger.GetLogger(LoggerType.MongoLogger);
            this.Container.ComposeParts(this);
        }
    }
    
    [Export(typeof(IService))]
    public class MyService : IService
    {
    
        //adding pragma directive removes compiler warning of unassigned property/field
        //as these will be assigned by MEF import 
    #pragma warning disable
    
        [Import]
        private ILogger _logger;
    
    #pragma warning restore
    
    
        public MyService()
        {
            //logger will be instantiated by MEF
        }
    
        public void DoServiceWork()
        {
            _logger.Log("Starting service work");
        }
    }
    

    【讨论】:

    • 您能否详细说明一下,我不确定我是否关注 SomeInitClass 是什么,以及我的 Logger 将如何注入 MyService。
    • 添加了更多细节。
    • 在我的场景中,我需要用它的c-tor中的logger类型来实例化MyService,logger是通过ctor注入到MyService中的,在很多情况下,logger的类型对于不同的实例是不同的我的服务。在您的场景中,记录器在引导程序中被实例化,并且它是“硬编码”的,对于 MyService 的每个实例都是 MongoLogger。
    • 这是一个不同的用例,可以更改此解决方案以支持您的要求。您最初的问题是如何注入记录器实例,我想我已经回答了。如果我有时间,我会更新答案。
    • 我不认为你回答了这个问题,你的解决方案将记录器的创建从对象内部移动到 MEF 框架,它仍然非常耦合,注入的整个概念是不依赖于实现,而不是类型。
    猜你喜欢
    • 1970-01-01
    • 2021-02-09
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多