.Net插件框架Managed Extensibility Framework简介

yizhihongxing

.Net插件框架Managed Extensibility Framework(MEF)是一个用于在应用程序中使用插件的框架。它利用了C#语言的特性和CLR(共同语言运行时)的能力,为应用程序提供了一种灵活的架构,使得可以追加或更改应用程序中的功能,而无需重新编译或修改代码。

什么是MEF

MEF是Microsoft推出的,用于构建可扩展和高度可组合的应用程序的框架。MEF框架的作用是将一个应用程序分成许多小部分,每一部分都可以提供一个特定的功能。MEF框架允许我们在应用程序中使用插件,并且通过在代码中添加几行简单的指令,就可以实现扩展功能的追加或更改,在不修改现有代码的情况下,让应用程序具有更高的灵活性和可扩展性。

使用MEF框架的好处就是我们可以实现代码的解耦和组件的松散耦合。这意味着我们可以在应用程序中添加新的功能,而无需在应用程序中添加新的代码。

MEF的应用场景

MEF通常用于需要扩展性的应用程序。在这类应用程序中,我们希望有一种机制,使得在应用程序运行时,能够动态添加或替换功能。几个例子包括:

  • 插件式应用程序
  • 计算机辅助设计(CAD)软件
  • 视频编辑软件
  • 游戏引擎
  • 博客引擎

无论是哪种应用场景,都可以利用MEF框架来实现应用程序的扩展。

MEF的组成部分

MEF框架主要由4个部分组成,它们分别是:

  • Part
  • Export
  • Import
  • Container

严格按照这4个模块进行组装,我们可以将一个应用程序拆分成几个独立的部分,并在运行时动态地将它们整合起来。下面是这些部分的详细介绍:

Part

Part是一个被视为可供扩展的单元,通常是一个类、接口、方法或类型。在将Part加入MEF容器之前,Part必须标记为“可导出的”(Exportable)。一旦Part被标记为可导出的,它就可以被添加到MEF容器中。

Export

Export是一个可被Part导入的类型或对象。Export是Part被导出后的结果,可以被其他需要这些功能的应用程序组件引用。Export可以被定义为一个单一的值,也可以是一个数组,其类型通常是接口或对象。

Import

Import是Part所需要的Export的引用。Import用于描述Part所依赖的Export。Import可以是必需的、可选的或多个,代表Part所需要的Export的个数。

Container

Container是MEF框架的核心部分。它是一个用于管理和组合Export和Import的对象。Container可以让应用程序在运行时使用Export,而无需在代码中执行显式的实例化。

MEF的优点

MEF框架提供了许多有用的功能,这些功能可以减少复杂性并增强应用程序的灵活性和可扩展性。下面是MEF框架的几个优点:

  • 简化了插件的扩展。开发人员可以从容器中根据需要获取插件,而不必担心插件的具体实现方式。
  • 可以减少代码重复,从而提高代码的可维护性。
  • 可以用于替换应用程序的组件而不影响其他组件的运行。
  • 使用MEF可以大大增强应用程序的可测试性,因为开发人员可以轻松地模拟和替换Export。

MEF的示例说明

示例1:使用Export和Import特性,将方法定义为可导出和导入的插件

假设我们有一个应用程序,希望通过插件实现一些复杂的数学计算功能。在这个例子中,我们将定义一个名为IMathPlugin的接口,所有的数学计算都将继承这个接口。此外,为了能够将计算方法导出到应用程序中,请将IMathPlugin方法修饰为Export特性。

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

public interface IMathPlugin
{
    double Calculate(double x, double y);
}

[Export(typeof(IMathPlugin))]
public class AddPlugin : IMathPlugin
{
    public double Calculate(double x, double y)
    {
        return x + y;
    }
}

public class MainProgram
{
    [ImportMany(typeof(IMathPlugin))]
    public IMathPlugin[] Plugins { get; set; }

    public static void Main(string[] args)
    {
        var program = new MainProgram();
        program.Run();
    }

    public void Run()
    {
        var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);

        foreach (var plugin in Plugins)
        {
            Console.WriteLine(plugin.Calculate(10, 20));
        }
    }
}

在这个例子中,我们定义了一个AddPlugin类,它实现了IMathPlugin接口。我们将AddPlugin类标记为可导出的,并且在MainProgram中使用ImportMany特性导入了IMathPlugin接口。在MainProgram的Run方法中,我们可以使用CompositionContainer对象轻松地组合AddPlugin插件。

示例2:使用MEF插件框架,动态添加和移除UI插件

假设我们有一个支持插件开发的Windows桌面软件。在这个例子中,我们将演示如何使用MEF框架动态添加和移除UI插件。

首先,我们需要定义一个接口来表示UI插件:

using System.ComponentModel.Composition;

[InheritedExport]
public interface IUIPlugin
{
    void Initialize();
    void Unload();
}

此接口定义了两个方法:Initialize(初始化)和Unload(卸载)。Initialize方法用于初始化插件,而Unload方法用于卸载插件。我们使用InheritedExport特性将接口标记为可导出的。

然后,我们考虑如何实现一个可扩展的UI组件。

我们将定义一个窗体,这个窗体可以动态添加和删除UI插件。对于窗体的具体设计,我们将使用WPF。窗体的xaml代码如下:

<Window x:Class="MEF.PluginExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Button Name="AddPluginButton" Click="AddPluginButtonClick" Margin="5" Width="75">Add Plugin</Button>
            <Button Name="RemovePluginButton" Click="RemovePluginButtonClick" Margin="5" Width="75" IsEnabled="False">Remove Plugin</Button>
        </StackPanel>
        <Grid Grid.Row="1" Name="PluginContainer"/>
    </Grid>
</Window>

在这个窗体中,我们定义了一个名为PluginContainer的Grid控件,它将用于UI插件的加载和卸载。在Grid上面的工具栏中,我们添加了两个按钮:Add Plugin(添加插件)和Remove Plugin(删除插件)。这些按钮将允许我们动态添加和删除UI插件。

现在,我们需要在代码中实现这些按钮的逻辑。我们使用MEF框架的CompositionContainer对象来获取UI插件。具体实现如下:

using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

namespace MEF.PluginExample
{
    public partial class MainWindow : Window
    {
        private readonly CompositionContainer _container = new CompositionContainer();

        public MainWindow()
        {
            InitializeComponent();

            var catalog = new AggregateCatalog(
                new AssemblyCatalog(Assembly.GetExecutingAssembly()),
                new DirectoryCatalog(".")
            );
            _container.ComposeParts(this, catalog);
        }

        private void AddPluginButtonClick(object sender, RoutedEventArgs e)
        {
            var dialog = new Microsoft.Win32.OpenFileDialog
            {
                Filter = "Plugins (*.dll)|*.dll|All files (*.*)|*.*"
            };

            if (dialog.ShowDialog() != true) return;
            var assembly = Assembly.LoadFile(dialog.FileName);

            _container.Catalog.Catalogs.Add(new AssemblyCatalog(assembly));
            _container.ComposeParts(this);

            PluginContainer.Children.Clear();
            foreach (var plugin in _container.GetExportedValues<IUIPlugin>())
            {
                var button = new Button
                {
                    Content = plugin.GetType().Name,
                    Margin = new Thickness(5),
                    Tag = plugin
                };
                button.Click += PluginButtonClick;

                PluginContainer.Children.Add(button);
            }

            RemovePluginButton.IsEnabled = true;
        }

        private void PluginButtonClick(object sender, RoutedEventArgs e)
        {
            var button = (Button)sender;
            var plugin = (IUIPlugin)button.Tag;

            plugin.Initialize();

            button.IsEnabled = false;
            AddPluginButton.IsEnabled = false;
            RemovePluginButton.IsEnabled = true;
        }

        private void RemovePluginButtonClick(object sender, RoutedEventArgs e)
        {
            var selectedButton = (Button)PluginContainer.Children[0];
            var selectedPlugin = (IUIPlugin)selectedButton.Tag;

            selectedPlugin.Unload();
            _container.Catalog.Catalogs.Remove(_container.Catalog.Catalogs[_container.Catalog.Catalogs.Count - 1]);
            _container.ComposeParts(this);

            PluginContainer.Children.Clear();
            foreach (var plugin in _container.GetExportedValues<IUIPlugin>())
            {
                var button = new Button
                {
                    Content = plugin.GetType().Name,
                    Margin = new Thickness(5),
                    Tag = plugin
                };
                button.Click += PluginButtonClick;

                PluginContainer.Children.Add(button);
            }

            AddPluginButton.IsEnabled = true;
            RemovePluginButton.IsEnabled = false;
        }
    }
}

如上所述,我们使用MEF框架的CompositionContainer对象来获取可用的UI插件。在AddPluginButtonClick事件处理程序中,我们使用Microsoft.Win32.OpenFileDialog控件来获取用户选择的插件。然后,我们将插件的Assembly添加到MEF容器中,重新组合Parts,并初始化UI插件。对于AddPluginButtonClick事件处理程序中的剩余代码,我们使用C#的WPF技术来允许用户动态添加按钮并将插件添加到用户界面中。

对于RemovePluginButtonClick事件处理程序中,我们首先使用PluginContainer.Children[0]获取当前选定的按钮,然后使用Tag属性获取当前选定的插件。然后,我们卸载这个插件,并从反映目录中删除它。最后,我们重新组合Parts,并重新初始化用户界面中的所有插件。

总之,MEF插件框架是一个用于在应用程序中使用插件的灵活框架,它支持将应用程序进行拆分并重组成部分,追加或更改应用程序的功能,大大提高了应用程序的可扩展性。在使用MEF框架时,我们只需遵循上述规则并利用好框架提供的各种组件,便可轻松实现应用程序的扩展。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:.Net插件框架Managed Extensibility Framework简介 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • 基于使用BeginInvoke,EndInvoke异步调用委托的实现代码

    在讨论 “基于使用BeginInvoke,EndInvoke异步调用委托的实现代码” 之前,我们需要先了解一下委托的概念。 委托的概念 委托(Delegate)是 .NET Framework 的一项非常重要的特性,他是一个类型,可以看成是函数指针,但比函数指针更复杂。 委托类型可以看成是具有一个或多个参数的方法的引用。当需要使用事件或线程调用方法时,委托可…

    C# 2023年6月6日
    00
  • VS2010写的程序在自己电脑可以运行、其他电脑上不能运行的解决方案

    要解决”VS2010写的程序在自己电脑可以运行、其他电脑上不能运行”问题,一般需要排查以下几项: 编译环境的不同 缺少必要的依赖库 不同操作系统之间的兼容性问题 针对以上问题,可以考虑采取以下一些解决方案: 1. 采用静态链接方式 VS2010默认生成的程序是采用动态链接方式的,导致在其他电脑上运行时需要安装VC运行库或.NET Framework等依赖库。…

    C# 2023年5月15日
    00
  • asp.net输出重写压缩页面文件实例代码

    ASP.NET是一款常用的Web应用程序开发框架,提供了很多优秀的功能。其中,输出重写和压缩页面文件也是ASP.NET的一个很重要的功能。下面,我将向大家详细讲解“asp.net输出重写压缩页面文件实例代码”的完整攻略。 一、什么是输出重写 ASP.NET中,输出重写是一种技术,可以动态地修改应用程序输出的HTML代码。当ASP.NET处理应用程序时,会生成…

    C# 2023年5月31日
    00
  • C#实体对象序列化成Json并让字段的首字母小写的两种解决方法

    将C#实体对象序列化成Json并将字段的首字母小写有两种解决方法,一种是通过在类定义中使用DataMember属性,另一种是通过创建一个包含转换规则的自定义JsonConverter类。 1. 使用DataMember属性 我们可以在类定义中使用[DataContract]和[DataMember]特性,这样在序列化时会自动将所有被标记的属性转为小写。 us…

    C# 2023年5月31日
    00
  • 全面分析c# LINQ

    全面分析c# LINQ攻略 什么是LINQ LINQ代表语言集成查询。这是一个功能强大的.NET框架的一部分,允许我们使用一种声明性的方式查询各种数据源,例如SQL Server数据库,XML文档,本地集合,等等。 在C#中,我们可以使用LINQ查询编写任何类型生成器,List,Enumerable,Array或各种实体框架集合。 LINQ有什么优点 LIN…

    C# 2023年5月15日
    00
  • C# NullReferenceException解决案例讲解

    下面是C#NullReferenceException解决案例讲解的完整攻略: 一、什么是NullReferenceException? NullReferenceException 是 .NET Framework 程序中最常出现的异常类型之一。它通常被抛出,当代码尝试使用一个值为null的对象引用,或者尝试对一个空对象进行访问。这个异常在 C# 程序中很…

    C# 2023年5月14日
    00
  • ASP.NET Core基础之异常中间件

    ASP.NET Core 中间件是一种非常强大的工具,可以用于处理请求和响应。异常中间件是一种特殊的中间件,用于处理应用程序中的异常。以下是 ASP.NET Core 基础之异常中间件的完整攻略: 步骤一:创建 ASP.NET Core 应用程序 首先,需要一个 ASP.NET Core 应用程序。可以使用以下命令在 Visual Studio 中创建一个 …

    C# 2023年5月17日
    00
  • C# WinForm应用程序降低系统内存占用方法总结

    C# WinForm应用程序降低系统内存占用方法总结 简介 C# WinForm应用程序在运行过程中会消耗较多的系统内存,如果内存占用过高则会影响系统的反应速度,导致用户体验不佳。本篇文章将介绍降低C# WinForm应用程序内存占用的方法。 方法 1. 图片资源优化 图片资源占用大量内存,影响程序性能。对于C# WinForm应用程序,图片资源可以通过以下…

    C# 2023年6月3日
    00
合作推广
合作推广
分享本页
返回顶部