我编写第一个VS2005的Addin--Getter/Setter
www.diybl.com 时间 : 2008-06-23 作者:佚名 编辑:本站 点击: [ 评论 ]
最近公司用Castle框架开发系统,其中利用到了ORM-Nhibernate,和Hibernate类似,在hbm.xml生成对应的POJO类需要Getter/Setter来存取属性值。在eclipse中提供了getter & setter生成器,但是在VS2005中是没有的。网上搜索一番,决定自己编写Getter & Setter生成器插件(Addin)来替代重复的,无聊的Getter&Setter手工Coding.提高生产效率。步骤大致如下:
1)在VS2005中新建Addin项目,在其他项目类型->扩展性->Visual Studio外接程序,取名GetSetAddin;
2)按照VS2005提供的Wizard,一步一步Next,此处略。OK后,VS会自动将大部分的框架代码生成好,我们做的就是填空式的将代码写在Connect.cs文件的方法Exec中。此方法就是用户选择我们自定义的菜单或工具栏按钮时触发的方法。
3)OnConnection方法用来注册菜单的。大部分代码和注释VS已帮我们生成,默认情况下,会在工具栏(Tool)中注册菜单。在这里我把菜单注册到编辑(Edit)菜单下。代码如下:
/// <summary>实现 IDTExtensibility2 接口的 OnConnection 方法。接收正在加载外接程序的通知。</summary> /// <param term='application'>宿主应用程序的根对象。</param> /// <param term='connectMode'>描述外接程序的加载方式。</param> /// <param term='addInInst'>表示此外接程序的对象。</param> /// <seealso class='IDTExtensibility2' /> public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) { _applicationObject = (DTE2)application; _addInInstance = (AddIn)addInInst; if (connectMode == ext_ConnectMode.ext_cm_UISetup) { object[] contextGUIDS = new object[] { }; Commands2 commands = (Commands2)_applicationObject.Commands; string toolsMenuName; try { //若要将此命令移动到另一个菜单,则将“工具”一词更改为此菜单的英文版。 // 此代码将获取区域性,将其追加到菜单名中,然后将此命令添加到该菜单中。 // 您会在此文件中看到全部顶级菜单的列表 // CommandBar.resx. ResourceManager resourceManager = new ResourceManager("GetSetAddin.CommandBar", Assembly.GetExecutingAssembly()); CultureInfo cultureInfo = new System.Globalization.CultureInfo(_applicationObject.LocaleID); string resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Edit"); toolsMenuName = resourceManager.GetString(resourceName); } catch { //我们试图查找“工具”一词的本地化版本,但未能找到。 // 默认值为 en-US 单词,该值可能适用于当前区域性。 toolsMenuName = "Edit"; } //将此命令置于“工具”菜单上。 //查找 MenuBar 命令栏,该命令栏是容纳所有主菜单项的顶级命令栏: Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"]; //在 MenuBar 命令栏上查找“工具”命令栏: CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName]; CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl; //如果希望添加多个由您的外接程序处理的命令,可以重复此 try/catch 块, // 只需确保更新 QueryStatus/Exec 方法,使其包含新的命令名。 try { //将一个命令添加到 Commands 集合: Command command = commands.AddNamedCommand2(_addInInstance, "GetSetAddin", "生成Getter&&Setter(&G)", "生成Get/Set属性", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); //将对应于该命令的控件添加到“工具”菜单: if ((command != null) && (toolsPopup != null)) { command.AddControl(toolsPopup.CommandBar, 1); } } catch (System.ArgumentException) { //如果出现此异常,原因很可能是由于具有该名称的命令 // 已存在。如果确实如此,则无需重新创建此命令,并且 // 可以放心忽略此异常。 } } } 这里有个问题需要注意,在VS2005中文版的开发环境下,默认生成在Tool菜单下注册自定义菜单,但是运行测试是看不到效果的,debug后才知道,取Tool菜单的Key是zhTools,而不是zh-CHSTools,所以在CommandBar.resx文件中加上zhTools(工具),在这里我加上的是zhEdit(编辑)。运行,OK,我们可以看到在编辑菜单下有个菜单【生成Getter&&Setter(&G)】,只是什么事情都没做。 4)在生成代码之前,需要获取到当前激活文档对象(FileCodeModel),像这样: private FileCodeModel ObtainCurrentFileCodeModel() { //获取当前正活动的文档 Document activeDocument = _applicationObject.ActiveDocument; if (activeDocument != null) { ProjectItem projectItem = activeDocument.ProjectItem; if (projectItem != null) { return projectItem.FileCodeModel; } } return null; } 获取后便可以遍历其中的元素,例如类,接口,属性,字段(变量),方法,命名空间,注释等等。下面的代码片断是递归获取所有类(在这里我们只需要获取类): private System.Collections.Generic.IList<CodeClass2> GetCodeClasses(CodeElements codeElements) { System.Collections.Generic.IList<CodeClass2> result = new System.Collections.Generic.List<CodeClass2>(); foreach (CodeElement2 ce2 in codeElements) { switch (ce2.Kind) { case vsCMElement.vsCMElementNamespace: CodeNamespace cn = (CodeNamespace)ce2; System.Collections.Generic.IList<CodeClass2> list = GetCodeClasses(cn.Members); foreach (CodeClass2 clazz in list) { result.Add(clazz); } break; case vsCMElement.vsCMElementClass: CodeClass2 cc = (CodeClass2)ce2; result.Add(cc); break; case vsCMElement.vsCMElementInterface: break; case vsCMElement.vsCMElementFunction: break; case vsCMElement.vsCMElementProperty: break; case vsCMElement.vsCMElementEvent: break; case vsCMElement.vsCMElementDelegate: break; case vsCMElement.vsCMElementStruct: break; case vsCMElement.vsCMElementEnum: break; case vsCMElement.vsCMElementAttribute: break; case vsCMElement.vsCMElementUsingStmt: break; case vsCMElement.vsCMElementVariable: break; } } return result; } 好了,得到了当前文档的所有类,那么接下来就是生成Getter&Setter方法,在此Addin项目中我用的一个Form,在其中用一个Tree来遍历了当前文档的所有类,并将类中的所有变量加入到子节点,由用户来选择生成哪些Getter&Setter,其界面参考的是eclipse的Getter&Setter生成器。如图所示: