65.9K
CodeProject 正在变化。 阅读更多。
Home

为 VS.NET 构建重构插件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (9投票s)

2003年7月2日

5分钟阅读

viewsIcon

114548

downloadIcon

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,它是使生活如此轻松的自动化对象之一。此时,该方法需要做两件事:

  1. 找出变量的名称(这将成为新属性的名称)
  2. 重命名变量(在前面添加下划线)

看看可扩展性框架让这一切变得多么容易。

  // 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 即可。

最后一步是实际指定 getset 方法的主体。不幸的是,我还没有找到一个同样优雅且实际可用的方法。相反,以下代码只是粘贴了此处指定的原始代码。

  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 中生成类型化集合的文章。祝你愉快!

© . All rights reserved.