每周源代码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
在注册表项中显示如下:
Steve还在着手使用XUnit进行测试。他试着用ContextSpecification模式进行测试,我们也拭目以待他的测试能否顺利完成。这部分内容到现在为止还算是基础的。可以参考TaskCollectionSpecs.cs,以此为例。
总之,读之有趣,用之便捷。这是个非常有趣的工具,能让我快速清理和发送代码样本。我可能会用我的插件来扩展这个工具,将代码上传至我的博客,并在剪贴板中加入链接。那样撰写代码示例的博客也会变得更简单。