每周源代码42- Tree Trim、插件和MEF


[原文发表地址] The Weekly Source Code 42 – Tree Trim, Plugins, and MEF

[原文发表时间] 2009-05-20 01:41

我十分提倡大家尽可能多地阅读素材,因为如果要提升自我,使自己成为一名更好的作家,就必须勤读勤练笔。这是《每周源代码》的初衷——勤读代码,有助于成为更高水准的程序开发者。

勤读开放式源码项目中的代码是一种很好的学习方法,尤其是对于存在多时且成功的项目,或者是你所尊重的团队成员所做的项目。就算你对整个项目不甚了解,至少,通过检索和共享代码,你能找到一些代码片段。

Tree Trim== CleanSources++

多年前,Omar Shahine编写了一个非常棒的小程序,叫做Clean Sources。它在Windows浏览器原有基础上添加了右键菜单功能,可以方便你删除bin, obj 和安装文件夹。

之后,Jeff 又编写了Clean Sources Plus,新增了“清除和打包”选项,同时支持移除源代码管理绑定。

如今,Steve Dunn也在此基础上继续扩展,新创了Tree Trim。这是一个命令行工具,拥有上述所有功能并新加了更多功能。他在原有基础上扩展并包含了一个插件模型,使其能在各插件间建立一个小小的通道。这样,你就能将插件链接起来,并用你自己的插件扩展命令行。而MEF(Managed Extensibility Framework: 托管扩展框架)则是其核心。

对于做构建的服务器,使用Tree Trim能够很方便地在你需要拷贝文件,删除源代码管理绑定,打包文件,邮件传送等时候发挥作用。

每个命令行参数是一个“任务”,而每个参数(别称)则映射到不同的目标对象。

treetrim.console.exe c:\dev\myproject -workingCopy -deleteFromDisk -zip –email

参数的顺序问题非常重要。参数保证所有的插件运行有序,比如:先拷贝,再删除bin/obj,打包,然后发送邮件。

制作你自己的插件 熟练掌握MEF

他有一个IPlugin插口:

   1: public interface IPlugin
   2:  
   3: {
   4:  
   5: string Moniker { get ; }
   6:  
   7: string WorkingPath { get ; }
   8:  
   9: void Cleanup( ) ;
  10:  
  11: void Run(IPluginRuntimeSettings settings, IPlugin lastPlugin);
  12:  
  13: }

制作插件时,你要让MEF知道类型导出是可行的:

   1: [Export(typeof(IPlugin))]
   2:  
   3: public class SomePlugin : IPlugin
   4:  
   5: {
   6:  
   7: ...
   8:  
   9: public string Moniker
  10:  
  11: {
  12:  
  13: get { return @"newPluginArgument" ; }
  14:  
  15: }
  16:  
  17: ...
  18:  
  19: }

然后同一目录下的所有插件都会被拉到插件清单中

   1: public DiscoverPluginsInAssemblyDirectory( )
   2:  
   3: {
   4:  
   5: var catalog = new DirectoryCatalog(disk.DirectoryOfExecutingAssembly);
   6:  
   7: var container = new CompositionContainer(catalog);
   8:  
   9: var batch = new CompositionBatch();
  10:  
  11: batch.AddPart(this);
  12:  
  13: container.Compose(batch);
  14:  
  15: }
  16:  
  17: [Import( typeof( IPlugin ) )]
  18:  
  19: public IList<IPlugin> Plugins
  20:  
  21: {
  22:  
  23: get;
  24:  
  25: set;
  26:  
  27: }

该应用程序通过导入的命令行参数和找到的插件来启动内部管道:

   1: Trimmer.TrimTree(
   2:  
   3: new TaskCollection( pluginDiscoverer.DiscoveredPlugins, commandLineArgs ),
   4:  
   5: path );

…然后…

   1: public static void TrimTree(ITaskCollection tasks, string sourceTreeRoot)
   2:  
   3: {
   4:  
   5: ITask lastTask = new Task { Plugin = new NullPlugin( sourceTreeRoot ) } ;
   6:  
   7: foreach ( ITask eachTask in tasks )
   8:  
   9: {
  10:  
  11: eachTask.Run( lastTask );
  12:  
  13: lastTask = eachTask ;
  14:  
  15: }
  16:  
  17: IEnumerable<ITask> reversedTasks = tasks.Reverse( ) ;
  18:  
  19: foreach (ITask eachTask in reversedTasks)
  20:  
  21: {
  22:  
  23: eachTask.Cleanup();
  24:  
  25: }
  26:  
  27: }

代码其实简单易懂,而且在Google Code中搜索TreeTrim首行就有显示,你也可以参考FAQ(常见问题)。有了MEF,插件问题就变得相当简单了。同时,Tree Trim在很多方面都给出了不错的示范。首先,它是作为一个广义上的插件,同时它又展现了给插件传递设置的技术。

为程序管理器添加环境菜单

在程序管理器中给这个(或任何其他)工具添加环境菜单很简单。操作如下:在注册表项中添加一个关键字。

HKEY_CLASSES_ROOT\Folder\shell\<WHATEVER TEXT YOU WANT>\command

然后在(默认)字符串中,如下输入(这里为一个示例):

"C:\Program Files (x86)\Tree Trim\TreeTrim.Gui.exe" "%1" -workingcopy -deletefromdisk – zip:writeTo: "c:\users\scott\desktop \justzipped.zip" +dontCleanUp

在注册表项中显示如下:

clip_image002

Steve还在着手使用XUnit进行测试。他试着用ContextSpecification模式进行测试,我们也拭目以待他的测试能否顺利完成。这部分内容到现在为止还算是基础的。可以参考TaskCollectionSpecs.cs,以此为例。

总之,读之有趣,用之便捷。这是个非常有趣的工具,能让我快速清理和发送代码样本。我可能会用我的插件来扩展这个工具,将代码上传至我的博客,并在剪贴板中加入链接。那样撰写代码示例的博客也会变得更简单。


Comments (0)

Skip to main content