Click here to Skip to main content
Click here to Skip to main content
Go to top

Building a Refactoring Plugin for VS.NET

, 1 Jul 2003
Rate this:
Please Sign up or sign in to vote.
This article describes how to develop a refactoring addin for Visual Studio.NET

Introduction

Whenever I code I regularly find myself in a situation where I need to turn a variable into a property. I know I should write all class attributes that are publicly visible as properties but it is more hassle than just declaring a variable public. To make my life easier I turned to Visual Studio's Extensibility framework and built an add-in that automates this exercise for me. Every VBA programmer knows that you can create routines within its office suite to automate everyday tasks. The same holds for Visual Studio. You can write macros using VBA and interact with the projects and files in your project. But you do not have to use VBA - you can write add-ins in your .NET language of choice. Being a right snob I write mine in C#.

Let's assume in my source file in visual studio I have a variable called Balance

public Currency Balance; 

To convert it into a property I place the cursor on the variable and select in the tool menu my menu item called 'Make Property'.

The result then should look as follows

public Currency Balance
{
  get { return _Balance;}
  set { _Balance = value;} 
}
private Currency _Balance;

Creating the Add-in Project in VS.NET

In the New Project Dialog  choose Other Project > Extensibility Projects > Visual Studio.Net Add-In and name it MkProperty.

The New Project Wizard then leads you through a series of questions such as what the add-in should be called in the tools menu. Make sure you check the 'create a tools menu item' option.

Once finished the wizard will create the appropriate class and set up the OnConnect routine which will ensure the add-in will be accessible through the tools menu.

Using the code

Now comes the interesting part. When the menu Make Property is called the Exec method is invoked. In the Exec method I call makeProperty()  From now on I will discuss what happens in bool makeProperty():

The first thing the method needs to do is to find where the cursor is and determine that it is located on a variable.

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);

....

This identifies a CodeElement that represents whatever is under the cursor. From there I  establish that this is a variable declaration and cast it to a CodeVariable 

  if (element.Kind == vsCMElement.vsCMElementVariable)
  {
     CodeVariable theVar = element as CodeVariable;

The variable named 'theVar' is a CodeVariable which is one of the automation objects that makes life so easy. At this point the method needs to do two things:

  1. Find out the name of the variable (which will become the name of the new property)
  2. rename the variable (by adding an underscore in front of it)

Look at how easy the Extensibility framework makes this:

  // get the variables name
  string propertyName = theVar.Name;
  // rename it 
  theVar.Name = "_" + propertyName;

Wasn't that easy??

The next step is to retrieve the accessibility (the new property needs to have the same accessibility) and to change it to a private variable.

  vsCMAccess propertyAccess = theVar.Access;
  // make the variable private
  theVar.Access = vsCMAccess.vsCMAccessPrivate;

Now the method has to create the property. In preparation it has to get the type of the variable and to determine the CodeElement that represents the owning class:

  string varTypeName = theVar.Type.AsString;
  CodeClass classElement = theVar.Parent as EnvDTE.CodeClass;

As you might expect, the CodeElement of the owning class is the parent of the CodeElement representing the variable.

 Now to create the property:

  CodeProperty newProperty = classElement.AddProperty(
    "A", "A", varTypeName,element,propertyAccess,element);
  newProperty.Name = propertyName;

If you are starting to get confused by the parameters in this call, don't worry. Here we are getting to the rougher edges of the Automation framework.

The first two parameters "A" and "A" are the getter and setter names for the property. As they are anonymous functions in C# we don't have to worry about them. The third parameter is the type which is the same type as the original variable. The fourth parameter gives the position. As we want to insert the property right next to the variable it is sufficient to simply provide the CodeElement representing the variable.

The last step is to actually specify the bodies of the get and set methods. Unfortunately I have not been able to find a similarly elegant approach that actually worked. Instead the following code simply pastes in the raw code that is specified here.

  string getExpression = "get {  return " +  var.Name + "; }";
  EditPoint ep = newProperty.Getter.StartPoint.CreateEditPoint();
  ep.ReplaceText(newProperty.Getter.EndPoint, 
       getExpression, vsEPReplaceTextOptionsAutoFormat);

While this is ugly compared to the previous bits it does redeem itself by providing the option to nicely format the code upon inserting it.

What is left now is to compile and deploy. VS.NET helps a lot, but sometimes it gets itself into a knot. Make sure you read the instructions in the generated code to help you out in case things go all out of shape.

When you build and run the project VS.NET will start another copy of itself. You should find in the Tools menu an entry called MakeProperty. Open a project (not just a file, it has to be a project otherwise the CodeElements won't be accessible) and place the cursor over a class variable. Select Tools->Make Property and voila! 

Points of Interest

When you create the project, the Wizard also creates an installation project. If you get in a knot with VS.NET and it starts misbehaving then select the install project, right click and select Uninstall in the popup menu.

Likewise, before completing the project, fill in the properties in the install project with a project name and your company name. This will affect the behaviour of the created MSI file as it takes these two parameters to determine the install path.

At the bottom of the source file you will find a routine called message(string msg). This is a simple utility that outputs a message into the VS.NET window called Output.

There is a lot of information in the Visual Studio.NET HELP. You will find it in:

Visual Studio.NET
  Developing with Visual Studio.NET
    Manipulating the Development Environment
and
    Reference

Next time I'll be writing an article on generating typed collections in VS.NET. Cheers

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Stephan Meyn
Web Developer
Australia Australia
I am a Software Engineer/Consultant. My work is focussed on helping teams to get more out of their work. So I teach how to do requirements, analysis and design in a format that is easy to understand and apply.
I help with testing too, from starting developers on automated unit testing to running whole testing teams and how they cooperate with development.
 
For really big projects I provide complete methodologies that support all of the lifecycle.
 
For relaxation I paddle a sea kayak around Sydney and the Central Coast or write utilities on rainy days to make my life easier.

Comments and Discussions

 
Generalmanipulation of FunctionBody Pinmembersebastian_der_kleene17-Aug-06 0:06 
GeneralRe: manipulation of FunctionBody PinmemberStephan Meyn17-Aug-06 2:09 
QuestionHow do we remove from the .NET IDE? Pinmemberrcm830721-Apr-06 3:53 
GeneralCan´t see the MakeProperty Add in in the tools menu PinmemberSebastian Streiger11-May-05 3:21 
GeneralRe: Can´t see the MakeProperty Add in in the tools menu PinmemberStephan Meyn11-May-05 13:07 
GeneralRe: Can´t see the MakeProperty Add in in the tools menu PinmemberSebastian Streiger12-May-05 2:04 
GeneralIn VB.NET huge problem PinsussRickardR17-Mar-05 1:17 
GeneralRe: In VB.NET huge problem PinsussRickardR17-Mar-05 1:22 
GeneralDoesn't work for files in folders PinmemberKeeper of the Forest12-May-04 14:32 
GeneralCodeElement property. PinsussScott Munro22-Apr-04 1:48 
GeneralDoes not work for codeelements other than variables Pinmemberminja7-Mar-04 19:03 
GeneralRe: Does not work for codeelements other than variables PinsussAnonymous8-Mar-04 23:36 
GeneralA small request PineditorMarc Clifton8-Jul-03 2:11 
AnswerRe: A small request PinmemberBPSchwind7-Mar-06 11:07 
GeneralMakeProperty does not show up PinmemberChristian Weyer5-Jul-03 10:52 
GeneralRe: MakeProperty does not show up PinmemberStephan Meyn6-Jul-03 2:41 
GeneralRe: MakeProperty does not show up PinmemberChristian Weyer6-Jul-03 7:25 
GeneralRe: MakeProperty does not show up Pinmembertonga10-Jul-03 8:51 
GeneralRe: MakeProperty does not show up PinmemberStephan Meyn14-Jul-03 22:19 
GeneralRe: MakeProperty does not show up PinmemberAnna-Jayne Metcalfe17-Jul-03 4:02 
GeneralRe: MakeProperty does not show up PinmemberTheCSharpener15-Jul-03 12:15 
GeneralRe: MakeProperty does not show up PinmemberHenke7221-Jun-04 21:51 
GeneralNice! Pinmemberdratti2-Jul-03 2:51 
GeneralSchweet PinsitebuilderPaul Watson2-Jul-03 2:07 
GeneralRe: Schweet PinmemberStephan Meyn3-Jul-03 3:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140905.1 | Last Updated 2 Jul 2003
Article Copyright 2003 by Stephan Meyn
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid