什么是MEF最佳实践?

Sor*_*oot 23 .net silverlight mef

在代码中使用MEF的最佳做法是什么?在启动可扩展应用程序时是否有任何陷阱需要考虑?你有没有遇到过你早先应该知道的事情?

Sco*_*ock 7

我正在MEF上构建一个完全成熟的可扩展应用程序(并使用带有MVVM模式的WPF).我采用了我构建的基本应用程序框架,并将其作为SoapBox Core开源.我还在Code Project上发布了一个基于SoapBox Core的演示:使用MEF,WPF和MVVM构建可扩展应用程序.

我不确定使用MVVM是否适用于您,但如果确实如此,那么通过查看使用MEF的MVVM实现,您可以学到很多东西.特别是它导入视图的方式.

至于最佳实践......我创建了一个嵌套的扩展层次结构(因此基本模块称为Host,它所做的只是组成应用程序并导入一些基本扩展).然后,这些扩展会暴露其他扩展点,并且在运行它时构建自身的应用程序类型(组合和扩展之间的交叉).

为了保持一切顺利,我将扩展层次结构放入一组静态类中.例如,以下是核心框架提供的所有扩展点:

namespace SoapBox.Core.ExtensionPoints
{
    public static class Host
    {
        public const string Styles = "ExtensionPoints.Host.Styles";
        public const string Views = "ExtensionPoints.Host.Views";
        public const string StartupCommands = "ExtensionPoints.Host.StartupCommands";
        public const string ShutdownCommands = "ExtensionPoints.Host.ShutdownCommands";
    }
    public static class Workbench
    {
        public const string ToolBars = "ExtensionPoints.Workbench.ToolBars";
        public const string StatusBar = "ExtensionPoints.Workbench.StatusBar";
        public const string Pads = "ExtensionPoints.Workbench.Pads";
        public const string Documents = "ExtensionPoints.Workbench.Documents";

        public static class MainMenu
        {
            public const string Self = "ExtensionPoints.Workbench.MainMenu";
            public const string FileMenu = "ExtensionPoints.Workbench.MainMenu.FileMenu";
            public const string EditMenu = "ExtensionPoints.Workbench.MainMenu.EditMenu";
            public const string ViewMenu = "ExtensionPoints.Workbench.MainMenu.ViewMenu";
            public const string ToolsMenu = "ExtensionPoints.Workbench.MainMenu.ToolsMenu";
            public const string WindowMenu = "ExtensionPoints.Workbench.MainMenu.WindowMenu";
            public const string HelpMenu = "ExtensionPoints.Workbench.MainMenu.HelpMenu";
        }
    }

    public static class Options
    {
        public static class OptionsDialog
        {
            public const string OptionsItems = "ExtensionPoints.Options.OptionsDialog.OptionsItems";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您希望扩展程序向文件菜单添加内容,则可以导出实现IMenuItem的内容,其中包含合同名称SoapBox.Core.ExtensionPoints.Workbench.MainMenu.FileMenu

每个扩展名都有一个"ID",它只是一个字符串标识符.这些现有ID在另一个层次结构中定义:

namespace SoapBox.Core.Extensions
{
    public static class Workbench
    {
        public static class MainMenu
        {
            public const string File = "File";
            public const string Edit = "Edit";
            public const string View = "View";
            public const string Tools = "Tools";
            public const string Window = "Window";
            public const string Help = "Help";

            public static class FileMenu
            {
                public const string Exit = "Exit";
            }

            public static class ViewMenu
            {
                public const string ToolBars = "ToolBars";
            }

            public static class ToolsMenu
            {
                public const string Options = "Options";
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,FileMenu已经包含一个Exit扩展(预编程为关闭应用程序).如果要在"文件"菜单中添加扩展名,可能需要在"退出"菜单项之前显示该扩展名.IMenuItem继承自IExtension,它有两个属性:

  • InsertRelativeToID
  • BeforeOrAfter

因此,您的扩展将为InsertRelativeToID返回SoapBox.Core.Extensions.Workbench.MainMenu.FileMenu.Exit,并为BeforeOrAfter属性(枚举)返回Before.当工作台导入所有文件菜单扩展时,它会根据这些ID对所有内容进行排序.通过这种方式,后面的扩展相对于现有扩展插入自身.


Hud*_*awk 6

最佳做法是使用Shared(单例)模型.这使我们考虑到设计因素,建议您将可导出部件设计为无状态和线程安全,这样它们就不会受到同一实例上多次调用(可能在不同线程上)的影响.

如果单例模型不适合您,建议使用构建器模式(将导出的部分与实际实例化分开).您应该记住,使用非共享模型是非常昂贵的,因为它使用反射进行实际实例化(通过使用构建器模式,您可以获得相同的结果,减少痛苦).

另请查看http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-toc.aspx 和cource你知道你可以在这里找到信息:http: //mef.codeplex.com