在代码中使用 MEF 的最佳实践有哪些?启动可扩展应用程序时是否有需要考虑的陷阱?你有没有遇到任何你应该早点知道的事情?
最佳答案
我正在 MEF 上构建一个成熟的可扩展应用程序(并使用带有 MVVM 模式的 WPF)。我将自己构建的基本应用程序框架开源为 SoapBox Core 。我还在代码项目中发布了一个基于 SoapBox Core 的演示:Building an Extensible Application with MEF, WPF, and MVVM .
我不确定使用 MVVM 是否适用于您,但如果适用,那么通过使用 MEF 查看 MVVM 的实现,您可能会学到很多东西。特别是它导入 View 的方式。
就最佳实践而言...我创建了一个嵌套的扩展层次结构(因此基本模块称为 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";
}
}
}
因此,如果您希望扩展程序向文件菜单添加某些内容,您可以导出使用合约名称 SoapBox.Core.ExtensionPoints.Workbench.MainMenu.FileMenu 实现 IMenuItem 的内容
每个扩展都有一个“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";
}
}
}
}
正如您所看到的,FileMenu 已经包含一个 Exit 扩展(已预先编程为关闭应用程序)。如果您想向"file"菜单添加扩展名,您可能希望它出现在“退出”菜单项之前。 IMenuItem继承自IExtension,它有两个属性:
- 插入RelativeToID
- 之前或之后
因此,您的扩展将为 InsertRelativeToID 返回 SoapBox.Core.Extensions.Workbench.MainMenu.FileMenu.Exit,并为 BeforeOrAfter 属性(枚举)返回 Before。当工作台导入所有文件菜单扩展时,它会根据这些 ID 对所有内容进行排序。这样,后面的扩展就会相对于现有扩展插入自己。
关于.net - MEF 最佳实践是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2738052/