文章参考:在MEF中实现延迟加载部件  作者:TianFang

仅有一个服务提供者时候

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; namespace 延迟加载
{
interface ILogger
{
void Log(string message);
}
[Export(typeof(ILogger))]
class ConsoleLogger : ILogger
{
public void Log(string message)
{ Console.WriteLine("logger 1" + message);
}
}
class Host
{
[Import]
//延迟加载
Lazy<ILogger> _logger;
//非延迟加载
//ILogger _logger;
public Host()
{
var catalog = new AssemblyCatalog(this.GetType().Assembly);
var container = new CompositionContainer(catalog); //如果不是延迟加载的话这儿会创建ConsoleLogger对象
container.ComposeParts(this);
//非延迟加载
//_logger.Log("logworld");
//延迟加载
_logger.Value.Log("hello world"); }
}
}

当某一组件并不是立刻需要使用,或者内存开销很大。影响程序加载的速度。比如当程序启动的时候。这个时候我们可以使用延迟加载,也就是只有当程序用到的时候才会去加载该部件。我们可以使用Lazy<T>来标记导入的类型。这样就简单的实现了延迟加载。

注意如果使用Lazy<T>来标记对象类型的话,需要通该实例的Value属性调用实例方法 _logger.Value.Log("hello world");

如果是非延迟加载

如果延迟加载:

当有多个服务提供者的时候

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
namespace 延迟加载
{
interface ILogger
{
void Log(string message);
}
[Export(typeof(ILogger))]
class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine("ConsoleLogger " + message);
}
} [Export(typeof(ILogger))]
class DbLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine("DbLogger " + message);
}
} class Host
{ //非延迟加载
//[ImportMany]
//ILogger[] _logger = null;
//延迟加载
[ImportMany]
Lazy<ILogger>[] _Lazylogger = null;
public Host()
{
var catalog = new AssemblyCatalog(this.GetType().Assembly);
var container = new CompositionContainer(catalog);
//非延迟加载此时会创建所有对象
container.ComposeParts(this);
//非延迟加载
//_logger.FirstOrDefault(i => i is DbLogger).Log("hello world");
//延迟加载,当调用的时候才创建对象,
//但是因为这儿有一个遍历,所以当调用一个对象的时候就会创建所以对象
_Lazylogger.FirstOrDefault(i => i.Value is DbLogger).Value.Log("DbLogger");
}
}
}

此时可以用ImportMany标记导入,同时用Lazy<T>包装我们的导入类型。但是此时有个问题,就是当我们如果通过类型遍历多个对象寻找可用导入时候,会创建所有对象。所以此时我们可以用元数据来判断是否使我们需要的导入。

通过元数据匹配需要的导入

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
namespace 延迟加载
{
interface ILogger
{
void Log(string message);
}
//通过标记元数据来标记导出服务
[ExportMetadata("Name", "Console Logger")]
[Export(typeof(ILogger))]
class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine("ConsoleLogger " + message);
}
}
//通过标记元数据来标记导出服务
[ExportMetadata("Name", "DbLogger")]
[Export(typeof(ILogger))]
class DbLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine("DbLogger " + message);
}
}
public interface ILoggerData
{
string Name { get; }
}
class Host
{
//延迟加载
[ImportMany]
Lazy<ILogger,ILoggerData>[] _Lazylogger = null;
public Host()
{
var catalog = new AssemblyCatalog(this.GetType().Assembly);
var container = new CompositionContainer(catalog);
//非延迟加载此时会创建所有对象
container.ComposeParts(this);
//延迟加载,当调用的时候才创建对象,
//但是因为这儿有一个遍历,所以当调用一个对象的时候就会创建所以对象
//_Lazylogger.FirstOrDefault(i => i.Value is DbLogger).Value.Log("DbLogger");
_Lazylogger.FirstOrDefault(i => i.Metadata.Name == "DbLogger").Value.Log("DbLogger"); }
}
}

通过元数据可以匹配我们需要的导出服务。但是,通过单纯的标记  [ExportMetadata("Name", "DbLogger")]很麻烦,而且属性笔记多的时候代码也不整洁。对此我们可以封装一个元数据特性

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
namespace 延迟加载
{
interface ILogger
{
void Log(string message);
}
//通过标记元数据来标记导出服务
[LoggerData("Console Logger")]
[Export(typeof(ILogger))]
class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine("ConsoleLogger " + message);
}
}
//通过标记元数据来标记导出服务
[LoggerData("DbLogger")]
[Export(typeof(ILogger))]
class DbLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine("DbLogger " + message);
}
}
public interface ILoggerData
{
string Name { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
class LoggerDataAttribute : Attribute, ILoggerData
{
public string Name { get; private set; } public LoggerDataAttribute(string name)
{
this.Name = name;
}
}
class Host
{
//延迟加载
[ImportMany]
Lazy<ILogger, ILoggerData>[] _Lazylogger = null;
public Host()
{
var catalog = new AssemblyCatalog(this.GetType().Assembly);
var container = new CompositionContainer(catalog);
//非延迟加载此时会创建所有对象
container.ComposeParts(this);
//延迟加载,当调用的时候才创建对象,
//但是因为这儿有一个遍历,所以当调用一个对象的时候就会创建所以对象
//_Lazylogger.FirstOrDefault(i => i.Value is DbLogger).Value.Log("DbLogger");
_Lazylogger.FirstOrDefault(i => i.Metadata.Name == "DbLogger").Value.Log("DbLogger"); }
}
}

本文地址:http://www.cnblogs.com/santian/p/4357324.html

博客地址:http://www.cnblogs.com/santian/

转载请以超链接形式标明文章原始出处。

MEF笔记 之延迟加载的更多相关文章

  1. 在MEF中实现延迟加载部件(转)

    在MEF的宿主中,当我们通过Import声明导入的对象时,组装(Compose)的时候会创建该对象.例如: interface ILogger    {        void Log(string  ...

  2. 在MEF中实现延迟加载部件

    在MEF的宿主中,当我们通过Import声明导入的对象时,组装(Compose)的时候会创建该对象.例如: interface ILogger    {        void Log(string ...

  3. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  4. MEF的学习笔记

    为什么要使用MEF 在商业应用软件开发过程中,对于各个软件项目,都需要建立相应的系统框架,为了更好的规范系统的开发,提高生产效率,应该在公司级别制定相应的API标准.这些API标准将站在系统架构层次, ...

  5. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  6. C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

    前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...

  7. C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

    上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...

  8. C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo

    在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架 ...

  9. [MEF]第03篇 MEF延迟加载导出部件及元数据

    一.演示概述此演示介绍了MEF的延迟加载及元数据相关的内容.在实际的设计开发中,存在着某些对象是不需要在系统运行或者附属对象初始化的时候进行实例化的,只需要在使用到它的时候才会进行实例化,这种方式就可 ...

随机推荐

  1. linux下GPRS模块ppp拨号上网

    ---------------------------------------------------------------------------------------------------- ...

  2. C#中的访问修饰符

    1. 简述 private. protected. public. internal 修饰符的访问权限.private : 私有成员, 在类的内部才可以访问.protected : 保护成员,该类内部 ...

  3. Java 字符串计算频率出现最高的字符

    public class HighFrequencyWord { public static void findFrequencyWord(String str) {          Collect ...

  4. Amazon EC2安装mysql多实例并配置主从复制

    1.MySQL安装: EC2直接使用yum安装mysql很方便: yum install mysql mysql-server mysql-libs 此处安装了三个包 完事之后可以直接使用 servi ...

  5. vue2自定义事件之$emit

    父组件: API上的解释不多: https://cn.vuejs.org/v2/api/#vm-emit vm.$emit( event, […args] ) 参数: {string} event [ ...

  6. nginx+vue实例纪录

    参考:http://www.cnblogs.com/wuac/p/6406843.html 新建工作目录vuepro,命令行之行命令:vue init webpack vue-test (项目默认的名 ...

  7. 2017.10.25 es-sql分页无效

    1.问题描述 使用es-sql聚合查询时,发现无法进行分页操作. 结果为16条: 当使用limit语法进行分页之后,发现并没有效果(以取5条记录为一页为例). 首先查询前5条记录: 返回的记录如下图: ...

  8. Unity学习笔记 之 关于 Unity UI 的 Slider 的代码记录

    代码例如以下: using UnityEngine; using System.Collections; //1.引入 UI . using UnityEngine.UI; public class ...

  9. Notepad++输入模式之改动模式、插入模式

    notepad++光标是直的,怎样让它变成竖的? 通常光标是竖的.为插入模式,光标在字符之间时输入,内容会随输入的内容向后移动,新输入的内容不会替换后面的内容. 当按一下"Insert&qu ...

  10. Java里的并发容器与安全共享策略总结

    一.并发容器 ArrayList --> CopyOnWriteArrayList 概念 : 简单的讲就是写操作时赋值,当有新元素添加到CopyOnWriteArrayList时,它先从原有的数 ...