为 VS.NET 构建重构插件






4.78/5 (9投票s)
2003年7月2日
5分钟阅读

114548

1461
本文介绍如何为 Visual Studio.NET 开发重构插件。
引言
每当我编码时,我经常会发现自己处于需要将变量转换为属性的情况下。我知道我应该将所有公开可见的类属性都写成属性,但这比仅仅声明一个公共变量要麻烦得多。为了让我的生活更轻松,我转向了 Visual Studio 的可扩展性框架,并构建了一个自动化这个过程的插件。每个 VBA 程序员都知道可以在其 Office 套件中创建例程来自动化日常任务。Visual Studio 也是如此。你可以使用 VBA 编写宏,并与项目中的项目和文件进行交互。但你不必使用 VBA——你可以用你选择的 .NET 语言编写插件。我是一个有点自负的人,所以我用 C# 编写了我的插件。
假设在 Visual Studio 的源文件中,我有一个名为 Balance 的变量。
public Currency Balance;
要将其转换为属性,我将光标放在变量上,然后在工具菜单中选择我称为“Make Property”的菜单项。
结果应该如下所示:
public Currency Balance
{
get { return _Balance;}
set { _Balance = value;}
}
private Currency _Balance;
在 VS.NET 中创建插件项目
在新建项目对话框中,选择其他项目 > 可扩展性项目 > Visual Studio.Net 插件,并将其命名为MkProperty。
新建项目向导将引导你完成一系列问题,例如插件在工具菜单中应如何命名。确保选中“创建工具菜单项”选项。
完成后,向导将创建相应的类并设置 OnConnect
例程,这将确保插件可以通过工具菜单访问。
使用代码
现在到了有趣的部分。当调用 Make Property 菜单时,会调用 Exec
方法。在 Exec
方法中,我调用 makeProperty()
。从现在开始,我将讨论 bool makeProperty()
中发生的情况。
该方法需要做的第一件事是找到光标的位置,并确定它位于一个变量上。
private bool makeProperty()
{
// identify where the cursor is
TextSelection selection =
(TextSelection) applicationObject.ActiveWindow.Selection;
// get the starting point
EditPoint Start = selection.TopPoint.CreateEditPoint();
// get the element under the cursor
CodeElement element = applicationObject.ActiveDocument.ProjectItem.
FileCodeModel.CodeElementFromPoint(Start,
vsCMElement.vsCMElementVariable);
....
这标识了一个 CodeElement
,它代表光标下的任何内容。从那里,我确定这是一个变量声明,并将其转换为 CodeVariable
。
if (element.Kind == vsCMElement.vsCMElementVariable)
{
CodeVariable theVar = element as CodeVariable;
名为 'theVar' 的变量是一个 CodeVariable
,它是使生活如此轻松的自动化对象之一。此时,该方法需要做两件事:
- 找出变量的名称(这将成为新属性的名称)
- 重命名变量(在前面添加下划线)
看看可扩展性框架让这一切变得多么容易。
// get the variables name
string propertyName = theVar.Name;
// rename it
theVar.Name = "_" + propertyName;
这不是很简单吗??
下一步是检索访问级别(新属性需要具有相同的访问级别),并将其更改为私有变量。
vsCMAccess propertyAccess = theVar.Access;
// make the variable private
theVar.Access = vsCMAccess.vsCMAccessPrivate;
现在该方法必须创建属性。作为准备,它必须获取变量的类型,并确定代表所有者的类的 CodeElement
。
string varTypeName = theVar.Type.AsString;
CodeClass classElement = theVar.Parent as EnvDTE.CodeClass;
正如你可能预期的那样,所有者类的 CodeElement
是代表变量的 CodeElement
的父级。
现在来创建属性。
CodeProperty newProperty = classElement.AddProperty(
"A", "A", varTypeName,element,propertyAccess,element);
newProperty.Name = propertyName;
如果你开始对这个调用中的参数感到困惑,别担心。在这里,我们遇到了自动化框架的粗糙边缘。
前两个参数“A”和“A”是属性的 getter 和 setter 名称。由于它们在 C# 中是匿名函数,所以我们不必担心它们。第三个参数是类型,与原始变量的类型相同。第四个参数给出了位置。由于我们想将属性插入到变量旁边,所以只需提供代表变量的 CodeElement
即可。
最后一步是实际指定 get
和 set
方法的主体。不幸的是,我还没有找到一个同样优雅且实际可用的方法。相反,以下代码只是粘贴了此处指定的原始代码。
string getExpression = "get { return " + var.Name + "; }";
EditPoint ep = newProperty.Getter.StartPoint.CreateEditPoint();
ep.ReplaceText(newProperty.Getter.EndPoint,
getExpression, vsEPReplaceTextOptionsAutoFormat);
虽然这与前面的部分相比显得有些丑陋,但它提供了在插入代码时对其进行良好格式化的选项,从而挽回了声誉。
现在剩下的是编译和部署。VS.NET 提供了很多帮助,但有时它会把自己搞得一团糟。请确保仔细阅读生成代码中的说明,以在事情出错时获得帮助。
当你构建并运行项目时,VS.NET 将启动另一个自身的副本。你应该在工具菜单中找到一个名为 MakeProperty
的条目。打开一个项目(不仅仅是一个文件,必须是一个项目,否则 CodeElements 将不可访问),并将光标放在一个类变量上。选择工具 -> Make Property,瞧!
关注点
当你创建项目时,向导还会创建一个安装项目。如果你在 VS.NET 中遇到麻烦并且它开始行为异常,请选择安装项目,右键单击并选择弹出菜单中的卸载。
同样,在完成项目之前,请在安装项目中填写项目名称和公司名称。这将影响创建的 MSI 文件的行为,因为它将这两个参数用于确定安装路径。
在源文件的底部,你会发现一个名为 message(string msg)
的例程。这是一个简单的实用程序,可以将消息输出到 VS.NET 的 Output 窗口。
Visual Studio.NET 帮助中有大量信息。你可以在此处找到它:
Visual Studio.NET
Developing with Visual Studio.NET
Manipulating the Development Environment
and
Reference
下次我将写一篇关于在 VS.NET 中生成类型化集合的文章。祝你愉快!