.NET中间件 -- MEF2

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);
        }
    }
    
    //契约名称为空,则不能发现指定了契约名称的ModelA
    var 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)

Managed Extensibility FrameworkMEF)是 .NET Framework.NET Core 中的一个插件化框架,可以帮助开发者实现可扩展的应用程序。MEF 框架在 .NET Core 中是自带的,不需要额外安装。 使用 MEF 框架实现插件化开发的步骤如下: 1. 创建插件接口 首先需要定义一个插件接口,该接口定义了插件的基本功能和方法。例如: ```csharp public interface IPlugin { string Name { get; } void Execute(); } ``` 2. 创建插件实现类 接着需要创建一个或多个实现插件接口的类。例如: ```csharp [Export(typeof(IPlugin))] public class Plugin1 : IPlugin { public string Name => "Plugin1"; public void Execute() { Console.WriteLine("Plugin1 executed."); } } [Export(typeof(IPlugin))] public class Plugin2 : IPlugin { public string Name => "Plugin2"; public void Execute() { Console.WriteLine("Plugin2 executed."); } } ``` 注意:实现类需要使用 `[Export]` 属性进行标记,表示该类是一个插件。 3. 创建主程序 创建主程序并使用 MEF 框架加载插件。例如: ```csharp class Program { static void Main(string[] args) { var catalog = new DirectoryCatalog("plugins"); // 插件目录 var container = new CompositionContainer(catalog); foreach (var plugin in container.GetExportedValues<IPlugin>()) { Console.WriteLine("Loaded plugin: " + plugin.Name); plugin.Execute(); } } } ``` 这段代码会从指定的插件目录中加载所有插件,并执行 `Execute` 方法。 注意:需要在主程序中添加对 `System.ComponentModel.Composition` 命名空间的引用,才能使用 MEF 相关的类。 这就是使用 MEF 框架实现插件化开发的基本步骤。在实际应用中,可以根据具体的需求进行更加复杂的插件实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值