.Net插件框架Managed Extensibility Framework简介

.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日

相关文章

  • C#事件(event)使用方法详解

    C#事件(event)使用方法详解 在C#语言中,事件(event)是一种能够向外界传递消息并触发特定操作的机制。本文将详细讲解C#事件的基本概念、使用方法和注意事项等内容,帮助读者更好的掌握事件处理。 基本概念 事件是一种特殊的委托类型,它能够在对象状态发生变化时,向监听者发送信号并触发相应操作。事件通常包含以下几个要素: 事件源:触发事件的对象。 事件参…

    C# 2023年5月31日
    00
  • 关于C#基础知识回顾–反射(三)

    关于C#基础知识回顾–反射(三)这篇文章的完整攻略如下: 一、反射简介 1.1 反射的概念 反射(Reflection)是指在程序运行的时候访问、检测和修改程序集中的元数据和对象的方式。反射用于访问 .NET 中的元数据,这种元数据描述了程序集(assembly)、模块(module)和类型(type)等。通过元数据,我们可以获取类型信息,了解类的结构和成…

    C# 2023年6月1日
    00
  • c#.NET 写txt文件小例子

    下面是详细的攻略: 1. 准备工作 在开始编写代码之前,需要准备好以下工具和环境: 电脑上已安装 .NET Framework。 某个文本编辑器或 IDE,比如 Visual Studio。 一些基本的 C# 编程知识。 2. 创建 C# 项目 创建一个新的 C# 项目: 打开 Visual Studio,选择 “新建项目”。 在弹出的 “新建项目” 窗口中…

    C# 2023年5月31日
    00
  • ASP.NET Core全面扫盲贴

    ASP.NET Core是一个跨平台的开源Web框架,它可以用于构建Web应用程序和服务。下面是ASP.NET Core全面扫盲贴的完整攻略。 什么是ASP.NET Core? ASP.NET Core是一个跨平台的开源Web框架,它可以用于构建Web应用程序和服务。它是ASP.NET的下一代版本,具有更高的性能、更好的可扩展性和更好的开发体验。 ASP.N…

    C# 2023年5月16日
    00
  • ASP.NET中Dictionary基本用法实例分析

    下面是ASP.NET中Dictionary基本用法实例分析的攻略: 概述 在ASP.NET中Dictionary是一种非常常用的数据结构,主要用于存储键值对。它可以帮助我们快速查询键对应的值,是一种高效的存储方式。本篇攻略将对ASP.NET中Dictionary的基本用法进行详细的讲解,并且提供两个实例来帮助理解。 Dictionary基本用法 创建Dict…

    C# 2023年6月3日
    00
  • 基于C#实现端口扫描器(单线程和多线程)

    基于C#实现端口扫描器(单线程和多线程) 端口扫描器是渗透测试和网络安全领域中一个非常重要的工具,它用于发现网络主机上开放的TCP/UDP端口。本文将基于C#实现一个简单的端口扫描器并探讨如何使用单线程和多线程技术来提高效率。 端口扫描器实现流程 解析待扫描主机的IP地址和端口范围 循环遍历端口范围,尝试向目标主机的每个端口发送TCP或UDP连接请求 根据返…

    C# 2023年5月15日
    00
  • Jquery上传插件 uploadify v3.1使用说明

    简介 uploadify是一个基于jQuery的多文件异步上传插件,可以提供灵活的文件上传功能。本文将详细介绍uploadify的使用方法和基本配置。 下载和引入 首先,需要下载uploadify插件,可以在官方网站http://www.uploadify.com/下载。下载后将js、css和swf文件放入相应目录,并在HTML文件中引入。 <link…

    C# 2023年5月31日
    00
  • C#对桌面应用程序自定义鼠标光标

    当我们需要在C#桌面应用程序中改变鼠标光标的默认外观时,可以使用C#编程语言中提供的Cursor类。下面是关于如何使用Cursor类来实现自定义鼠标光标的攻略: 导入命名空间 在使用Cursor类之前,需要先导入System.Windows.Forms命名空间。代码如下: using System.Windows.Forms; 加载自定义光标文件 在使用自定…

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