MEF官方解释 : MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。
作用: (1) 使用MEF是为了提高程序的可扩展性。MEF会根据指定的导入导出自动去发现匹配的扩展,获取到相应类型的对象,不需要进行复杂的程序配置
(2) 程序设计有几个原则,“高内聚,低耦合”就是其中一个。使用MEF可以帮助我们减少内库之间的耦合。
NuGet安装MEF2, 包名是 Microsoft.Composition,适用于 .NET Framework 4.5 及以上,.NET Core 和各种 .NET 移动平台
使用说明:添加引用System.Composition,
MEF 完全使用特性来管理容器中的依赖,Import/Export:在类型上标记 [Export]
可以让容器发现这个类型。[Export]
允许带两个参数,一个契约名称,一个契约类型。在 [Import]
的时候,相同的契约名称会被注入
示例:
1. 简单使用
类ModelA实现接口IModel,ModelA添加特性[Export(typeof(IModel))],创建Container容器管理依赖
namespace MEF.Interface{public interface IModel{void Do();} }namespace MEF.ViewModels{[Export(typeof(IModel))]public class ModelA : IModel{public void Do(){Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.FullName);}}}public class Container{private static Container _instance;public static Container Instance{get => _instance ?? (_instance = new Container());}public ContainerConfiguration Composition { get; set; }private Container(){//在Program类所在的程序集中,直接或间接加了 [Export] 特性的类都将被此依赖容器管理。Composition = new ContainerConfiguration().WithAssembly(typeof(Program).Assembly);}}class Program{public static IModel Model { get; set; }static void Main(string[] args){//创建容器var container= Container.Instance.Composition.CreateContainer();//获取实现IModel接口且有[Export(typeof(IModel))]标记的类的对象Model = container.GetExport<IModel>();Model.Do();Console.ReadKey();}}
输出:
2. 实现接口IModel的类有多个时,ModelA , ModelB
var models = container.GetExports<IModel>().ToArray();foreach (var item in models)
{item.Do();
}
输出:
3. 通过构造函数注入,在构造函数添加特性[ImportingConstructor]
public interface IView{void Show();} [Export(typeof(IView))]public class ViewA : IView{public Imodel Model { get; set;}[ImportingConstructor]public ViewA(IModel model) //实现IModel的类必须添加[Export]特性{Model = model; //通过构造函数注入对象}public void Show(){Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.FullName);Model.Do();}}var view= container.GetExports<IView>().FirstOrDefault();view.Show();
4. [ImportMany]导入多个实现了该接口的对象
[Export(typeof(IView))]public class ViewA : IView{public ObservableCollection<IModel> Model { get; }[ImportingConstructor]public ViewA([ImportMany]IEnumerable<IModel> model) //importmany:导入多个实现了该接口的类{Model = new ObservableCollection<IModel>(model);}public void Show(){Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.FullName);foreach (var item in Model){item.Do();}}}
输出:
5. 当实现接口的类有多个时,为方便管理,使用契约名称来筛选要导出导入的对象
[Export("ModelA",typeof(IModel))] 参数1:契约名称(按需求自己起) 作用:在Import的时候,添加契约,会导入指定含有契约名称的类,契约名可以重复(此时导入多个),这样一来,我们就可以用契约名给类进行分类,导入时可以根据契约名来导入。
public class ExtendA : IExtend[Export("ModelA",typeof(IModel))]public class ModelA : IModel{public void Do(){Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.FullName);}}//契约名称为空,则不能发现指定了契约名称的ModelAvar models = container.GetExports<IModel>().ToArray();//写入指定的契约名称,只能发现指定了相同契约名称的导出var models = container.GetExports<IModel>("ModelA").ToArray();
6. 导出的类添加特性 [Shared] ,使导出的类共享实例(实例只有一个)
public interface IExtend{void Init();int Num { get; set; }}[Shared] [Export("ext",typeof(IExtend))] public class ExtendA : IExtend{public void Init(){Num += 10;Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.FullName);Console.WriteLine($"Num : {Num}");}public int Num { get; set; }}var Extend_1 = container.GetExport<IExtend>("ext");Extend_1.Init();var Extend_2 = container.GetExport<IExtend>("ext");Extend_2.Init();
通过Num的值的变化简单说明共享实例,
不添加[Shared],输出:
添加[Shared],输出:
7. Lazy<>延迟初始化
[Export(typeof(IView))]public class ViewB : IView{/** Lazy<>延迟初始化:仅仅当对象第一次使用的时候,再初始化,如果一直没有调用,那就不初始化* 应用场景:1.对象创建成本高且程序可能不会使用它 2. 对象创建成本高,且希望将其创建推迟到其他高成本操作完成后* 只有在Lazy变量的Value属性被首次访问时对象才会真正的创建,该属性只读,因此仅有get访问器*/private readonly Lazy<IExtend> _extend; public IExtend Extend => _extend.Value;[ImportingConstructor] //构造函数导入public ViewB([Import("ext")] Lazy<IExtend> extend) //无锲约名称时,里面的import可以不写{_extend = extend;}public void Show(){Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.FullName);Extend.Init();}}
参考:
【1】Managed Extensibility Framework (MEF) | Microsoft Docs
【2】.NET Core 和 .NET Framework 中的 MEF2 - walterlv - 博客园 (cnblogs.com)
【3】C#进阶系列——MEF实现设计上的“松耦合”(一) - 懒得安分 - 博客园 (cnblogs.com)