引言
目前的软件并不是自动生成的,但是我们都知道软件将会一代代地发展下去。那么,为什么我们不努力于自动生成的软件,为什么不努力于创造能够一代代自动生长或发展使用的软件而却致力于改变现有的?目前我们所拥有的哪些技术能够支持生成的软件而遗忘了哪些技术呢?对这些问题的回答可能还不存在,但是VS 2005中已经具有一些能力来支持生成的代码了。
在Visual Studio 2005中,你可以使用宏来为你书写代码。这些宏代码生成器并不是随便生成的,而你也不必凭想象和发明来构划要写什么样的宏。两个独立但仍有联系的研究领域-设计模式和重构-明确地提供了许多的选择用于书写易理解的,具有良好文档的代码生成器(代码生成与生成的代码并不是一回事,这是在使用宏引擎时所必须要理解的)。本文将向你展示怎样使用Visual Studio 2005中的宏引擎创建一个代码生成器来为VB.net实现重构封装字段。
重构:封装字段
重构是一个为提高代码实现质量的定义过程。具体地说,重构是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。在最简单意义上,重构从代码中提取了一些主观性。作为软件工程师,我们不必再依赖于舆论和意志力来判断编码是好的还是不好的;我们能运用一个客观的标准并同意重构的代码优于非重构的代码。
就象设计模式一样,重构是命名的代码模式,带有充分的描述,指令,要想达到的结果。任何一个程序员,不管是否有开发经验,都能读取相应的描述,并象遵循医生的处方一样使用预先确定的指令,并取得可以预料的进步。
一个重构的例子称作封装字段。封装字段意指,使字段名成为私有的并通过公共的属性方法来限制到这些字段的存取。限制到一对象的状态的存取优于无限制的存取,封装字段正是基于相信对数据的限制存取所具有的价值(有些人可能还不同意基本的前提-有约束的存取优于自由的存取-而有些人还认为基于对象进行设计并没有多少好处,更不用争论重构是良性的还是非良性的问题了。不过,本文假定是良性的重构)。
实现宏
如果你正处于Visual Studio 2005的一个C#工程上下文中,那么一定会存在一个重构菜单。而在VB.net工程上下文中,是不存在这样的菜单的(至少到目前发行的beta 2版本中是如此)。然而,你能容易地为VB.NET仿效这种支持的行为-例如通过书写一个轻量级的代码生成器来实现封装字段(或其它重构)。
为了实现封装字段,自动化下列步骤:
1. 选择一个字段,不需要一个一致的属性方法。
2. 把字段的存取修饰词改成private。
3. 稍微改变一下该字段名以避免属性冲突(使用任何你喜欢的习惯)。
4. 生成getter/setter属性方法以及一些代码已提供对该字段的存取。
提示:开始用宏进行工作的一个好办法是打开宏记录器,完成一项任务,进而分析在集成开发环境中生成了哪些宏语句。然后,再进一步归纳录制下的宏。
Visual Studio对象模型支持所有这些能力,甚至还有更重要的能力。列表1展示封装字段的一个实现。
Imports EnvDTEImports EnvDTE80Imports System.DiagnosticsPublic Class RefactoringPublic Shared Sub EncapsulateField() Dim projectItem As ProjectItem = DTE.ActiveDocument.ProjectItem Dim fileCodeModel As FileCodeModel = projectItem.FileCodeModel "得到当前的选定内容 Dim selection As TextSelection = DTE.ActiveDocument.Selection "得到当前的光标位置 Dim point As TextPoint = selection.ActivePoint "尽量读取当前位置作为一个代码元素 Dim codeElement As CodeElement = fileCodeModel.CodeElementFromPoint( _ point, vsCMElement.vsCMElementVariable) If (codeElement Is Nothing) Then MsgBox("Place mouse cursor on field before running this macro.",_
MsgBoxStyle.Exclamation) Return End If Debug.Assert(codeElement.Kind = vsCMElement.vsCMElementVariable) "我们测试过了,所以知道这是个变量 Dim codeVariable As CodeVariable = CType(codeElement, CodeVariable) Dim fieldName As String = codeVariable.Name Dim fieldType As String = codeVariable.Type.AsString "重命名该字段,以使不发生属性冲突问题 codeVariable.Name = "F" & fieldName "确保字段是private codeVariable.Access = vsCMAccess.vsCMAccessPrivate "得到变量的parent Dim codeClass As CodeClass = CType(codeVariable.Parent, CodeClass) "添加一个新属性 Dim codeProperty As CodeProperty = codeClass.AddProperty("dummy",_
"dummy", fieldType, codeElement) codeProperty.Name = fieldName "实现getter Dim getter As EditPoint = codeProperty.Getter.GetStartPoint_
( vsCMPart.vsCMPartBody).CreateEditPoint getter.LineDown() getter.Indent(, 3) getter.Insert("Return " + codeVariable.Name) "实现setter Dim setter As EditPoint = codeProperty.Setter.GetStartPoint( _ vsCMPart.vsCMPartBody).CreateEditPoint setter.LineDown() setter.Indent(, 3) setter.Insert(codeVariable.Name + " = Value")End SubEnd Class