ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: Visual Studio Hacks

Hacking Visual Studio


Use ClickOnce to Deploy Windows Applications

Author's note: Following are some of the hacks from my book that stand out to me for different reasons. "Master the Command Window" (Hack #46) is one of the most time-saving and keyboard-friendly parts of Visual Studio. "Create Comments Faster" (Hack #69) is one of my favorite hacks since it covers one of my all-time favorite add-ins and is written by Roland Weigelt, creator of the add-in. "Run Unit Tests Inside Visual Studio" (Hack #93) covers one of my other top picks for add-ins, TestDriven.NET. It's one of the only add-ins that can really affect the way that you go about writing code. "Hack the Project and Solution Files" (Hack #4) is an interesting hack because it covers one of the undocumented parts of Visual Studio. I also selected "Refactor Your Code" (Hack #14) because it covers what I think is hands-down the best new feature in Visual Studio 2005, the Refactor menu.

Related Reading

Visual Studio Hacks
Tips & Tools for Turbocharging the IDE
By James Avery

Master the Command Window

Although Visual Studio is, er...well, rather visual, command-line junkies don't need to fear it.

Visual Studio has hundreds of menus, windows, and dialog boxes. This you are probably aware of; what you may not be aware of is that you can avoid using all of these and use the command line inside the command window instead. This hack looks at some of the different commands available to you, how to use existing aliases, and how to create and manage your own aliases.

Command Window Basics

So why would you want to use a command window when you could just use some part of the IDE? Using the command window is sometimes faster than using the IDE, and when you are writing code with both of your hands on the keyboard, it is often easier and faster to type a command than to reach for the mouse. Many people who are used to the good old days of the command prompt find themselves right at home with the command window, but whether or not you are one of these people, I encourage you to explore its functionality.

The main keystroke to remember is Ctrl-Alt-A (View.CommandWindow); this is the shortcut to open the command window.

The open command is the first command I am going to cover. Using the open command, you can open any file in either the filesystem or the current solution. (I think the real added value here is opening a file in the current solution, since the command window provides IntelliSense.) Figure 6-2 shows the command window and the IntelliSense available for the open command.


Figure 6-2. Command Window open command

This might not seem like much, but if you have a dozen projects with hundreds of files, this becomes much faster than digging through the Solution Explorer with your mouse.

You can use any Visual Studio command directly through the command window (through this book, whenever we mention a keyboard shortcut, we've also been mentioning the command). Any command can be used through the command window.

Twenty of the most useful commands are shown in Table 6-1. You can either type the full command or use the alias.

Table 6-1. Useful Visual Studio commands and aliases

Command

Alias

Description

File.OpenFile

open

Opens the file specified as a parameter

File.NewFile

nf

Creates and opens a new file

File.NewProject

np

Creates and opens a new project

File.AddNewProject

addProj

Creates and adds a new project to the current solution

File.SaveAll

SaveAll

Saves all the currently open files

File.Close

close

Closes the selected file

View.FullScreen

FullScreen

Switches to full-screen mode in the IDE

View.Toolbox

toolbox

Shows the toolbox window

View.PropertiesWindow

props

Shows the properties window

Edit.GotoBrace

GotoBrace

Skips to the corresponding brace (e.g., the closing brace of an if statement)

Edit.SelectAll

Selects all the text in the current document

Edit.Undo

undo

Equivalent to Edit → Undo

Edit.Redo

redo

Equivalent to Edit → Redo

Edit.NextBookmark

NextBook

Jumps to the next bookmark

Edit.PreviousBookmark

PrevBook

Jumps back to the previous bookmark

Edit.CollapsetoDefinitions

StopOutlining

Collapses all collapsible section of code (classes, regions, etc.)

Build.BuildSolution

build

Builds the current solution

Debug.Print

?

Shows the value of the variable passed in as a parameter

Debug.QuickWatch

??

Displays the quick watch dialog for the variables passed in as a parameter

Tools.Alias

alias

Lists all currently defined aliases or defines a new one

When in doubt, you can sometimes fall back on old MS-DOS command prompt habits: for instance, the command cls will clear the command window. You can find a complete list of commands in the Tools → Options → Keyboard screen [Hack #24] .

Debugging with the Command Window

Perhaps the most useful function of the command window is the ability to use it to view the values of variables during the debugging process. You can use a number of different commands during the debugging process to read and set the values of variables. You can simply type a question mark, a space, and then the name of a variable, and when you press Enter, the value of that variable will be printed to the screen. Here is an example of this command:

>? i
0

In this example, the value of the variable i is zero. You can also set the value of a variable through the command window by using the question mark, a space, the name of the variable, and then an equals sign and the value that you want to set the variable to. Here is an example of setting the value of a variable through the command window:

>? i =2
2

As an alternative to using the question mark, you can also set the command window to immediate mode; this turns the command window into an immediate window and you no longer need to use a question mark. You can set the command window to immediate mode by typing in the command immed. Following is a transcript of using the command window in immediate mode:

>immedi
0

To switch the command window back into command mode, you simply need to type in any command prefixed with >. For instance, you could type >cmd and the window would switch back to command mode.

Another benefit to viewing the value of a variable in the command window is that it is easy to copy the value of that variable out of the command window. If you are working with a large string of XML, it might be valuable to get the value of that XML document and then copy it to your favorite XML application to view the data in a friendlier format.

Create Window Aliases

Aliases are a way of creating a custom command that is short for a longer command. The Open command shown earlier is actually an alias that Visual Studio defines for the more verbose command File.OpenFile. To create new aliases you simply need to type alias, the name of the alias, then the command that you want to execute for this alias. Here is an example of creating an alias for the Edit.SelectAll command:

>alias selectall Edit.SelectAll

You can now select all the text on the screen by calling the alias selectall. You can also create aliases that include a parameter for a command. You can create a command called openClass1 that calls the File.OpenFile command and also specifies which file to open. Here is an example of this command:

>alias openClass1 File.OpenFile Class1.cs
>openClass1

This way you can call the openClass1 command at any time to open the Class1.cs file. You can also remove aliases that you have already created by simply adding the /delete switch at the end of the alias command. Here is an example of how to remove the openClass1 alias:

>alias openClass1 /delete

View and Edit Command Window Aliases

While you can create and edit aliases directly in the command window, the VSTweak power toy provides an easy-to-use graphic interface for these command window aliases. Using this interface, you can add, edit, or delete command window aliases.

The VSTweak power toy is one of the more useful power toys for Visual Studio and is the subject of a number of different hacks in this book. The VSTweak power toy [Hack #13] can be downloaded from http://workspaces.gotdotnet.com/vstweak. Figure 6-3 shows an example of this interface.


Figure 6-3. The VSTweak Alias Manager

Using the Alias Manager, you can create, edit, and delete aliases using a nice graphical interface. The Available Commands button will show all of the available commands that you can create aliases for. The View File button shows the aliases.ini file, which stores all of the command window aliases.

The command window offers a lot of features that can be used to increase your productivity while working with Visual Studio, particularly when debugging.

Create Comments Faster

There are boring parts of the XML commenting process that you can automate to make documentation more fun (and more likely to happen).

The problem with XML documentation comments is that somebody has to write them. Even worse, often enough that someone is you. The Visual Studio IDE helps you by preparing an empty template when you type /// in front of a method, but in the end you still have to fill in the blanks.

Here's an example. Imagine a method "AppendHtmlText" that is used to append HTML text to some sort of buffer. This method has several overloads, and one of these overloads has a parameter of type "HtmlProvider". This is what Visual Studio will create when you start writing a new XML documentation comment:

/// <summary>
///
/// </summary>
/// <param name="htmlProvider"></param>

public void AppendHtmlText(HtmlProvider htmlProvider)
{
    ...
}

You would then add your text, so the XML documentation comment could, for example, look something like this:

/// <summary>
/// Appends the HTML text of the specified provider.
/// </summary>
/// <param name="htmlProvider">The HTML provider.</param>

public void AppendHtmlText(HtmlProvider htmlProvider)
{
    ...
}

This is a typical method that comes by the dozen: the method name pretty much says what it is doing and you definitely do not need much imagination to write the comment—after some time, these methods become a real drain to document. On the other hand, you simply have no choice. If you want the benefits of XML documentation comments (perhaps a nice help file generated by NDoc [Hack #71] ), you have to comment all public (and protected) members, period.

Let's take a closer look at the earlier example. The method is written according to Microsoft's Design Guidelines for Class Library Developers; some of these rules are:

Now when you look at this set of rules on one hand and the documentation you have written on the other, it is pretty safe to say that a large part of the documentation could have been generated automatically.

GhostDoc

GhostDoc is an add-in for Visual Studio .NET 2003 that tries to do just that. With GhostDoc installed, you move the cursor into the method or property you want to document, invoke the Document This command using either the source editor's context (right-click) menu or a hotkey, and GhostDoc will create an XML documentation comment. The result for the previous example would be:

/// <summary>
/// Appends the HTML text.
/// </summary>
/// <param name="htmlProvider">The HTML provider.</param>

public void AppendHtmlText(HtmlProvider htmlProvider)
{
    ...
}

Pretty close—but how does GhostDoc do that? First of all, it's important to note that the add-in has no idea of what the identifiers actually mean—GhostDoc simply assumes that the code is written according to the guidelines and does the following:

After GhostDoc has created the XML documentation comment, the developer has to edit only a few details (for example, for the AppendHtmlText method, add "using the specified provider" to the end of the sentence) before moving on to the really interesting part of the documentation: remarks on usage, references to related methods or properties, example code—information that cannot be created automatically.

GhostDoc is driven by generation rules. When an XML documentation comment is about to be generated, the add-in will collect information about the code element (method, property, indexer, etc.) like name, return type, parameter names and types, and so on. This information is then compared to a set of rules, and the rule that fits best is then used to generate the documentation.

With each version of GhostDoc, the number of rules grows; the more specialized they are (for example, rules for handling Boolean properties, methods with a name consisting of only one word, etc.), the better the results.

Here are a few more examples that show only a part of what GhostDoc can automatically generate:

Documentation for an indexer

Note that the rule for indexers takes the name of the parameter into account, so it is "at the specified index", but "with the specified name":

/// <summary> /// Gets the <see cref="System.String"/> at the specified index. 
/// </summary> /// <value></value> public string this[int index] 
{ 
    get { ... } 
}

Boolean properties with a name consisting of only one word

If you comment Boolean properties in .NET Framework documentation style, you will definitely recognize the "Gets or sets a value indicating whether..." rule, and most likely you already have stopped counting the times you have typed this phrase:

/// <summary> /// Gets or sets a value indicating whether 
/// this <see cref="Demo"/> is cool. 
/// </summary> /// <value> /// <c>true</c> if cool; otherwise, <c>false</c>. 
/// </value> public bool Cool 
{ 
    get { return true; } 
    set { ; } 
}

A method with "of the" reordering for method and parameter names

The so-called "of the" reordering is triggered by specific words such as "size," "length," or "name" (the list of trigger words can be configured):

/// <summary> /// Determines the size of the page buffer. 
/// </summary> /// <param name="initialPageBufferSize">

/// Size of the initial page buffer.</param> 
/// <returns></returns> 
   public int DeterminePageBufferSize(int initialPageBufferSize)

Getting Started

First, you will need to download and run the GhostDoc installer from http://www.roland-weigelt.de/ghostdoc.

After running the GhostDoc installer, the next time you start Visual Studio, a couple of configuration dialogs appear to complete the setup (for example, choose a hotkey). Note that GhostDoc cannot install a hotkey if Visual Studio is not already using a custom keyboard scheme—this is a limitation of Visual Studio's extensibility model. If you are not sure, simply try to assign a hotkey; if GhostDoc setup encounters a problem, it will tell you what to do.

GhostDoc comes with a C# source file that demonstrates the features of this add-in; simply load the demo project, which can be found in a subdirectory of the folder GhostDoc was installed to. Inside Visual Studio, open the Demo.cs C# file, move the cursor into the body of a method, for example, and invoke the Document This command. The Document This command can be invoked using the hotkey, from the right-click menu, or from Tools → GhostDoc → DocumentThis.

After you invoke the Document This command, GhostDoc will go to work and generate as much of your XML comments as it can.

Tweaking GhostDoc

Certain aspects of GhostDoc can be configured:

You can edit the configuration settings in the dialog that is opened Tools → GhostDoc → Configure GhostDoc. This dialog is shown in Figure 8-2.


Figure 8-2. GhostDoc Configuration dialog

In this dialog, you can also export settings to a file that can then be imported on a different computer. This is pretty handy if, for example, you want to keep the configurations at home and at work in sync.

Roland Weigelt

Run Unit Tests Inside Visual Studio

Testing can be just a few clicks away when you use TestDriven.NET to run unit tests right inside of Visual Studio.

Test Driven Development is the practice of writing unit tests for your code before you actually write that code. By writing a test and then writing the code to make that test pass, you have a much better idea of the goal and purpose of your code. Test Driven Development also encourages complete code coverage, which not only increases the quality of your code, but also allows you to refactor the internals of a method or class and quickly and easily test the outside interface of the object.

TestDriven.NET is a unit-testing add-in for Visual Studio. It was developed for a number of years under the name NUnitAddIn. It now supports multiple unit testing frameworks and is compatible with all versions of Visual Studio .NET. It is available in free and professional versions from the TestDriven.NET web site at http://www.testdriven.net. Its author, Jamie Cansdale, keeps a web log charting TestDriven.NET's development at http://weblogs.asp.net/nunitaddin.

Installing

TestDriven.NET can be installed using an administrator or limited user account. By default, it will install for just the current user. Because limited users don't have write access to the Program Files folder, a limited user installation will install files in the user's Application Data\TestDriven.NET folder. An administrator installation will install files in the Program Files\TestDriven.NET folder. These defaults can be changed by selecting Custom on the Choose Setup Type page.

TestDriven.NET is packaged with functional versions of the NUnit and MbUnit unit testing frameworks. It also includes an adapter for executing Visual Studio Team System unit tests when available. These will be installed to subdirectories inside the TestDriven.NET directory, as shown in Figure 13-2.


Figure 13-2. TestDriven.NET Setup

Run Test(s)

The Run Test(s) command offers a straightforward way to build and run tests. It is intended to be the default method of test execution in most contexts. It automatically detects the test framework being used and executes tests using the correct test runner. The tests are launched by a test execution engine running as an external process. This test process is kept alive in order to improve execution times on subsequent runs. Once a test process has been cached, a rocket icon will appear in the notify box.

If the code editor window is selected, the test(s) to execute will be determined by the position of the caret. Individual tests are executed by right-clicking anywhere inside a test method and selecting Run Test(s), as shown in Figure 13-3. All tests in a test fixture are executed by right-clicking inside a class (but outside of any method) and selecting Run Test(s). All tests in a namespace are executed by right-clicking inside a namespace and selecting Run Test(s).


Figure 13-3. Run Test(s) menu item

The Run Test(s) option is also found on various Solution Explorer context menus. It can be used to execute all tests in a solution, project, or project item.

Ad Hoc Tests

Ad hoc tests offer a useful alternative to throwaway console applications. They should not in any way act as a substitute for real unit tests. Rather, they are intended to provide a convenient way of exploring local private methods or third-party code.

Any method that does not take parameters can be executed as an ad hoc test simply by right-clicking inside it and selecting Run Test(s). It can be a public, private, static, or instance method. In the case of an instance method, an object will be created using the default constructor of the class (providing, of course, that the class has a default constructor). The Dispose method will be called on any object that implements IDisposable, once the test has been executed.

If an ad hoc test returns an argument, the argument will be expanded to the Test output pane. Complex objects will have their fields and properties displayed. Enumerable objects will be listed. Primitive objects will be converted to strings and displayed.

Test Output and Task List

The Test output pane is the window in which all test results and warning messages appear and is shown in Figure 13-4. Trace and debug information is also sent there, along with console output and error messages. If all tests in a project or solution are being executed, the Test output pane will display only ignored or failed tests.


Figure 13-4. Output Test pane

When a test fails, the name of the test, together with the exception message and stack trace, is displayed. If code has been compiled with debugging information, the corresponding portions of the stack trace will contain line numbers. Double-clicking on these portions is a convenient way of navigating to the offending code.

As well as sending information to the output pane, failing tests also get added to the task list. If many tests have failed, this creates a useful summary view as shown in Figure 13-5. Generally, the further up the stack trace, the more likely the code will be of interest. Double-clicking a test in the task list is an alternative way of accessing the code in question.


Figure 13-5. Task List view

Test With... Debugger

The Test With... menu offers many alternative contexts in which to run tests. Selecting the Debugger context executes test(s) with the Visual Studio debugger attached, as shown in Figure 13-6. By setting a breakpoint on a method and selecting Test With... → Debugger, it is possible to step into a unit test.


Figure 13-6. Debugger command on Test With... submenu

By default, Visual Studio will build all projects in a solution when executing with the debugger. In Visual Studio .NET 2003 and Visual Studio 2005, there is an option to "Only build startup projects and dependencies on Run". Checking this option can significantly improve startup times when debugging large solutions. In Visual Studio .NET 2003, this option is under Tools → Options → Environment → Projects and Solutions. In Visual Studio 2005, it can be found under Tools → Options → Environment → Projects and Solutions→Build and Run.

Test Projects and Solutions

By right-clicking on a project in the Solution Explorer window and selecting Run Test(s), all tests within that project will be executed. Failed and ignored tests are sent to the Test output pane and task list in a similar fashion to other Run Test(s) commands. Trace, debug, and console output is suppressed when executing all tests in a project or solution.

Similarly, all tests in a solution can be executed by right-clicking on the solution in the Solution Explorer window and selecting Run Test(s). For each project in the solution, the test framework being used is established and tests are executed using the correct test runner. Projects that do not contain any tests are simply ignored.

Aborting a Test Run

When a test run is in progress, an Abort Test menu item will appear on the Tools menu, as shown in Figure 13-7. Selecting this item will abort the thread the tests are executing on. When tests are aborted in this way, any cleanup logic is given a chance to run.


Figure 13-7. Abort Test command on Tools menu

Stopping the Test Process

You will sometimes need to stop the test process. The most common of these circumstances is when an app domain is created, but not unloaded by a test run. This can result in any assemblies loaded by the app domain being locked, which causes subsequent builds to fail. It is possible to recycle the test process by right-clicking on the rocket icon in the notify box and selecting Stop, as shown in Figure 13-8. A new test process will be launched the next time the Run Test(s) command is executed.


Figure 13-8. Stopping the test process

Jamie Cansdale

Hack the Project and Solution Files

Discover the format of these two Visual Studio files and learn about a tool to convert these files between versions of Visual Studio.

Solution and project files are an essential part of working with Visual Studio. You will almost always work with the solution and project files through the IDE, whether adding projects to your solution or configuring your project. The purpose of this hack is to describe the format of these files for two reasons. If your project or solution files become corrupted, knowing the structure of these files might help you fix the file without having to re-create the entire project or solution. Also, knowing the structure of these files will help you if you want to convert these files or write a tool that works directly with these files.

WARNING You must edit these files with extreme care. The format of these files is not published or documented and could change drastically in future versions. You should normally need to work with these files only through the IDE, and unless you find a compelling reason to, I would not directly edit these files. If you are interested only in converting the version of these files, then you may want to look toward the end of this hack under Section 1.5.3 to read about a tool that will do the conversion for you.

Solution Files

Visual Studio creates two separate files when you create a new solution in Visual Studio. The first file is the .suo (solution user options) file, which stores user settings such as the location of your breakpoints. This file is stored in binary format, which does not lend itself to easy editing. Since there are no compelling reasons to edit this file, I am not going to document the format of it here. If you think that this file is preventing your solution from opening, you can actually delete the file and Visual Studio will create a new one when you open the solution and save it when you close the IDE. By deleting the file, you will lose any of your user-specific settings like breakpoints, but this is a small price to pay for saving your solution. The .suo file is a hidden file, so you will need to make sure Windows Explorer is configured to show hidden files (this can be set through Tools → Folder Options → View in any Explorer window).

The second file that Visual Studio creates is the .sln file. This file stores information about the projects that make up this solution, source control settings, and other global settings that apply to all of the projects in the solution.

The first line of the solution file contains a declaration including the version of Visual Studio that this solution is built for:

Microsoft Visual Studio Solution File, Format Version 8.0

The version number used in the solution file is a little different than the version number you are used to seeing in the Visual Studio product name. Visual Studio .NET 2002 solution files have a version number of 7.0. Visual Studio .NET 2003 solution files have a version number of 8.0 (as opposed to the 7.1 number you are used to), and Visual Studio 2005 solutions files have a version number of 9.0. Visual Studio 2005 Beta 1 contains an additional line under this first line, which contains just the following:

# Visual Studio 2005

This line causes the icon of the file to be changed to a Visual Studio 2005-specific icon, and if removed, will prevent Visual Studio from opening this file when you double-click on it.

The next portion of the solution file contains a section for each of the projects that are contained in this solution:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HacksWinApp", 
"HacksWinApp\HacksWinApp.csproj", 

"{75B7D1AE-1896-409D-B717-64D9AFCF0F59}"
    ProjectSection(ProjectDependencies) = postProject
        {89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4} = 
        {89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4}
    EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HacksLib", 
"HacksLib\HacksLib.csproj", "{89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4}"
    ProjectSection(ProjectDependencies) = postProject
    EndProjectSection
EndProject

You can see that the syntax of the file is somewhat similar to Visual Basic. Each project has a Project and EndProject tag as well as a ProjectSection tag to track the dependencies for the project. The first GUID in the project tag is used to identify what type of project this is. In this instance, the GUIDs for both a C# Windows Forms project and a C# library project are the same, since these project types are really the same except for the output type setting. The strings on the right side of the equals sign include the name of the project, its path relative to the solution root, and the unique GUID for this project. This GUID is used for a number of things including tracking dependencies.

TIP: You can view a list of all the project GUIDS by opening regedit (Start → Run, then type regedit) and navigating to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.1\Projects.

Under this key are all the GUIDs for the project available on your machine; the name and the extension of the project are listed as well.

In Visual Studio .NET 2003 and Visual Studio 2005, project dependencies are also tracked here. These are not the implicit dependences that are created by project references. When Project A references Project B, there is an implicit dependency. Project B must be built before Project A since it references the other project's output. Since this type of dependency is project-specific information, it is stored in the project file. (In this example, it would be stored in Project A's project file since it is referencing Project B, rather than the solution file we are looking at here.) Project files and dependencies are described in the next section.

The dependences stored in the ProjectSection tag are configured at the solution level. They define when a project must be built before another project, but they may not directly reference each other. This is stored in the ProjectSection tag of the project that is dependent on the other project. In this example, the HacksWinApp project is dependent on the HacksLib project and thus includes a reference to the GUID of the other project. This dependency is normally configured by right-clicking on the solution file, selecting Properties from the context menu, and navigating to Project Dependencies in the property page that appears.

Visual Studio .NET 2003 includes a ProjectSection tag even if there is no dependency (you can see this in the HacksLib project tag). Visual Studio 2005 completely omits the ProjectSection tag if there are no dependencies for the project. Visual Studio .NET 2002 stores the dependency information in a completely different section of the solution file, which we will cover next.

The next section in the solution file is the Global section, which begins with a Global tag and ends with an EndGlobal tag. Inside these tags are a number of GlobalSection tags that store an array of different pieces of information, including the configuration settings for various projects as well as source control information. Here is a look at the Global section of this example solution file from Visual Studio .NET 2003:

Global
    GlobalSection(SolutionConfiguration) = preSolution
        Debug = Debug
        Release = Release
    EndGlobalSection
    GlobalSection(ProjectConfiguration) = postSolution
        {75B7D1AE-1896-409D-B717-64D9AFCF0F59}.Debug.ActiveCfg 
         = Debug|.NET
        {75B7D1AE-1896-409D-B717-64D9AFCF0F59}.Debug.Build.0 
         = Debug|.NET
        {75B7D1AE-1896-409D-B717-64D9AFCF0F59}.Release.ActiveCfg 
         = Release|.NET
        {75B7D1AE-1896-409D-B717-64D9AFCF0F59}.Release.Build.0 
         = Release|.NET
        {89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4}.Debug.ActiveCfg 
         = Debug|.NET
        {89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4}.Debug.Build.0 
         = Debug|.NET
        {89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4}.Release.ActiveCfg 
         = Release|.NET
        {89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4}.Release.Build.0 
         = Release|.NET
    EndGlobalSection
    GlobalSection(ExtensibilityGlobals) = postSolution
    EndGlobalSection
    GlobalSection(ExtensibilityAddIns) = postSolution
    EndGlobalSection
EndGlobal

The SolutionConfiguration and ProjectConfiguration sections contain the build configuration settings for the solution and its projects. The ExtensibilityGlobals and ExtensibilityAddIns sections are included for the benefit of add-in authors. The ExtensibilityGlobals section can be used to store global information about the solution, and the ExtensibilityAddIns section lists all the add-ins that are used in this solution.

Visual Studio .NET 2002 also uses the Global section to store information about project dependences. Here is an example of that configuration section:

GlobalSection(ProjectDependencies) = postSolution
        {1C19F285-69AF-409E-8D5B-A354B68B41FF}.0 
        = {CBBAD9B0-CB56-44CA-8312-A9258F2061E2}
EndGlobalSection

This section simply specifies that the project identified by its GUID on the left of the equals sign depends on the project identified by its GUID on the right side of the equals sign.

Visual Studio 2005 includes an additional section that is not present in any of the older versions of Visual Studio; it's shown here:

    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
    EndGlobalSection

If the FALSE is switched to TRUE, then the solution node is hidden in the IDE.

Project Files

Each project creates a number of files to store information about itself. This includes a project file and a user settings file. The extension for the project file is based on the language type; for example, a C# Project is saved with the extension .csproj and a VB.NET Project is stored with the extension .vbproj. Thankfully, the internal formats of these various files are based on the same XML schema. The beginning of each project file includes some basic information about the project, including the version of Visual Studio that it was created for as well as the GUID for this project. Here is an example of this section:

<VisualStudioProject>
<CSHARP
        ProjectType = "Local"
        ProductVersion = "7.10.3077"
        SchemaVersion = "2.0"
        ProjectGuid = "{89EE0E8E-C5C6-4772-A5EE-D347E40FB0E4}"

    >

This is from a Visual Studio .NET 2003 project file, which is why the ProductVersion is set to 7.1 and the SchemaVersion is set to 2.0. In Visual Studio .NET 2002, the ProductVersion would be 7.0 and the SchemaVersion would be 1.0. These settings are no longer relevant in Visual Studio 2005 as project files are now MSBuild files.

TIP: Notice that the version number used for Visual Studio .NET 2003 is 7.1 in the project file and 8.0 in the Solution file.

The next section of the project file is the Build section, which includes build settings and configuration settings as well as references information. Here is the Build settings section:

<Build>

    <Settings
         ApplicationIcon = ""
         AssemblyKeyContainerName = ""
         AssemblyName = "HacksLib"
         AssemblyOriginatorKeyFile = ""
         DefaultClientScript = "JScript"

         DefaultHTMLPageLayout = "Grid"
         DefaultTargetSchema = "IE50"
         DelaySign = "false"
         OutputType = "Library"
         PreBuildEvent = ""

         PostBuildEvent = ""
         RootNamespace = "HacksLib"
         RunPostBuildEvent = "OnBuildSuccess"
         StartupObject = "">

As you can see, this section includes information like the AssemblyName and OutputType of the project. The next part of the Build section is for the various build configurations:

<Config
    Name = "Debug"
    AllowUnsafeBlocks = "false"
    BaseAddress = "285212672"

    CheckForOverflowUnderflow = "false"
    ConfigurationOverrideFile = ""
    DefineConstants = "DEBUG;TRACE"
    DocumentationFile = ""
    DebugSymbols = "true"

    FileAlignment = "4096"
    IncrementalBuild = "false"
    NoStdLib = "false"
    NoWarn = ""
    Optimize = "false"

    OutputPath = "bin\Debug\"
    RegisterForComInterop = "false"
    RemoveIntegerChecks = "false"
    TreatWarningsAsErrors = "false"
    WarningLevel = "4"/>

This section includes configuration-specific build settings. The project file will usually contain at least a Debug and Release section. The next part of the Build section contains all of the references for this project. Here is an abbreviated example of this section:

<References>
    <Reference
     Name = "System"

     AssemblyName = "System"
     HintPath = "..\..\..\..\..\..\..\..\..\..\WINDOWS\Microsoft.NET\
                 Framework\v1.1.4322\System.dll"
</References></Build>

The References section contains a reference tag for each assembly referenced by the project. Starting with Visual Studio 2005, you can create a reference to either an assembly or an executable, which comes in very handy when you are trying to unit-test a Windows application, since this lets you directly reference your application. To get this same functionality in Visual Studio .NET 2003, you can actually hack the project file to create a reference to an executable—you simply need to manually enter a reference tag in the references element pointing to your executable. Your new reference tag would look exactly like this example, except it would be pointed to an .exe file instead of a .dll file.

After the Build section is theFiles section of the project file, which can be seen here:

<Files>
            <Include>

                <File
                    RelPath = "AssemblyInfo.cs"
                    SubType = "Code"
                    BuildAction = "Compile"
                />
                <File
                    RelPath = "Class1.cs"

                    SubType = "Code"
                    BuildAction = "Compile"
                />
            </Include>
        </Files>

    </CSHARP>
</VisualStudioProject>

This section simply tracks all of the files that are included in this project. The schema of the project file is pretty straightforward in case you need to edit it directly.

Visual Studio also creates a user-specific project file much like the .suo file created for the solution file except with an extension of <projectextension>.user, so if you were using VB.NET, it would be vbproj.user. Similarly, this user-specific file does not contain anything pertinent enough to cover here, and is also hidden by default, so you will need configure Windows Explorer to show hidden files through Tools → Folder Options → View.

Visual Studio 2005 has not been mentioned up until this point because the project files in Visual Studio 2005 are completely different than the project files in Visual Studio .NET 2002 and 2003. The project files in Visual Studio 2005 are MSBuild XML files. MSBuild is the new build tool used in Visual Studio 2005 and is a completely different, complex topic that is not going to be covered here. It is similar to NAnt in that is uses XML files to describe how the project should be built.

Project and Solution File Conversion

Visual Studio does an excellent job of converting files from older versions to newer versions. For instance, if you open a Visual Studio .NET 2002 solution in Visual Studio .NET 2003, it will first ask if you want to convert the solution. After you say yes, it will convert all of your solution and project files to the new version of Visual Studio .NET. Now what if you accidentally converted those files and didn't have a backup? Or perhaps you are writing a solution in Visual Studio .NET 2003 and find out that your client has only Visual Studio .NET 2002? One method would be to create a new solution in the old version, create an identical project structure, and then copy all the files over and add them to their respective projects. Thankfully, there is a better solution. There is a tool available that will automatically convert the project and solution files for you as well as the .resx files if you are using Windows Forms.

The tool is called Visual Studio Converter 2.0 and can be downloaded from http://www.codeproject.com/macro/vsconvert.asp.

This tool is simple to use. Figure 1-15 shows an example of this conversion tool's user interface.


Figure 1-15. Visual Studio Converter 2.0

To convert files, you first need to click the Add Files button and select all the solution, projects, and .resx files for your solution. For a simple, one-form C# Windows Forms application, you would need to include the .sln, .csproj, .csproj.user, and Form1.resx. You will have an additional .resx file for each form in your application. Next, you need to click one of the two conversion buttons to convert the files to either Visual Studio 7.0 (2002) or Visual Studio 7.1 (2003). When initially converting a 2002 project to the 2003 format, it is best to use the Visual Studio conversion process. After this initial process, this tool is a great way to convert the files back and forth as needed.

Currently, it converts only between Visual Studio .NET 2002 and Visual Studio .NET 2003.

Refactor Your Code

Visual Studio 2005 puts this fundamental tenet of Extreme Programming into action. Use it to write better code.

Refactoring is a technique for improving a section of code by modifying its internal structure, but without affecting its external behavior. Refactoring is one of the key tenets of Extreme Programming; in a rapid development methodology, the idea is to create code quickly and then refactor it as you work with it. The goal of Extreme Programming is to create better quality code by concentrating on small deliverables and continuously testing and refactoring your code. Refactoring is not just limited to Extreme Programming—it is a valuable practice regardless of the methodology you happen to subscribe to. Visual Studio 2005 introduces a new Refactor menu. This menu is available whenever you right-click and provides a number of time-saving and code-improving functions.

TIP: Refactoring is almost exclusively a C# feature. The only part of the Refactor menu that is available in VB.NET is the Rename function.

Figure 2-31 shows the menu and the various functions included there.


Figure 2-31. Refactor menu

Extract Method

The first function available in the Refactor menu is Extract Method. This can be used to select a block of code and then extract that code into a separate method. This function has a number of applications, such as removing a section of code that deserves to be in its own method for code reuse purposes. Here is some existing code:

public class Car
{
    private bool _isStarted = false;
    private bool _hasFuel = true;
  
    public Car( )
    {
        //Start the Car
         if (_hasFuel){_isStarted = true;}
    }
}

That example has a little bit of code in the constructor that checks to see if the car has fuel and then "starts" the car by setting a Boolean value. If you decide that this class needs a second constructor, instead of duplicating this tiny piece of logic, you could extract this into a separate StartCar method and then call that method from both constructors. To accomplish this with the Refactor menu: highlight the code you want to extract and then right-click and select the Extract Method function from the Refactor menu. After you select Extract Method, you see a dialog box that asks for the name of the new method (see Figure 2-32).


Figure 2-32. Extract Method dialog

Type in the new name of the method, in this case, StartCar, since it describes exactly what the method will accomplish. After you click OK, Visual Studio will modify the selected code by placing it in a new method named StartCar, then placing a call to the new method in the spot where the old code was. Here is the new code:

public Car( )
{
    //Start the Car
    StartCar( );
}
  
private void StartCar( ){if (_hasFuel){_isStarted = true;}}

Rename

The second function on the Refactor menu is the Rename function. This is one of the most time-saving functions on this menu. Suppose that you decide the name Car is a little shortsighted, since the system will need to work for Cars, Bikes, Trucks, and more. A more appropriate name would be Vehicle. Normally you would need to manually find all references to the name Car and change them; the Rename function does this for you automatically. First, right-click on the name Car and then select the Rename function from the Refactor menu; the Rename dialog will then be displayed (see Figure 2-33). The Rename dialog allows you to specify what to rename the class to; in this case, it's going from Car to Vehicle. A number of checkboxes are available; check all of them in this example. The first (Preview Reference Changes) lets you preview all of the changes to the files; the next two checkboxes (Search In Comments/Strings) tells Visual Studio to search for this name in comments as well as strings.


Figure 2-33. Rename dialog

After clicking the OK button, you will see a confirmation dialog that shows all of the changes that will be made. As you can see in Figure 2-34, the Preview Changes dialog shows where Visual Studio is going to change the name Car to Vehicle. After you click Apply, Visual Studio will make all the changes to the project.

WARNING One thing that Visual Studio does not change is the name of the StartCar method. Since Visual Studio does not look in method names when making these changes, you will have to change StartCar to StartVehicle yourself.


Figure 2-34. Preview Changes dialog

In addition to being a great time-saver, Rename removes any excuse you might make about why a class is not named appropriately.

Encapsulate Field

The Encapsulate Field function creates a public property that encapsulates your field. In the ongoing example, suppose that you need to create a public property for the _isStarted field. To do this, right-click on the field name and click the Encapsulate Field function on the Refactor menu. You are then shown the Encapsulate Field dialog, which is shown in Figure 2-35.


Figure 2-35. Encapsulate Field dialog

Visual Studio automatically sets the property name to be IsStarted and gives you the option to update references to the old field. Leave this setting as External so that code in your class is not changed to reference the public property and instead continues to use the private field. The other checkboxes are similar to the ones you saw in the Rename dialog and perform the same actions. After you click OK, you are shown a Preview Changes dialog--the same kind of dialog shown in Figure 2-34—which shows all of the changes that will result. After you accept the changes shown, the following code is added to the class:

public bool IsStarted
{
    get
    {
        return _isStarted;
    }
  
    set
    {
        _isStarted = value;
    }
}

This function comes in handy even when you are not refactoring. When creating a class for the first time, you can create the private fields and then use this function to create all of the necessary public properties.

Extract Interface

The Extract Interface function looks at your current class and creates an interface based on its public methods and properties. For example, suppose you want to create an interface for objects that can be "started"; this interface would include a Boolean property, in this case IsStarted, which, when set, has the side effect of "starting" the object (some kind of vehicle or item with an on/off switch). First, right-click on the class name and click the Extract Interface menu item; this displays the Extract Interface dialog, which is shown in Figure 2-36.


Figure 2-36. Extract Interface dialog

The default interface name is IVehicle; change it to IStart and then select the IsStarted property. After you click OK, Visual Studio creates a new file called IStart.cs with the following piece of code:

interface IStart
{
    bool IsStarted { get; set; }
}

Visual Studio will also modify the existing class to implement the new interface. The Extract Interface function is a great time-saver when you need to create an interface that is based on a current class.

Parameter Functions

The next three functions on the menu all focus on working with parameters. Since the sample class does not currently contain any methods with parameters, go ahead and add a new method with a number of different parameters. Here is a method called Collision that you can add to this class:

public void Collision(DateTime CrashDate, int Speed, int DamagePct)
{
    int costMultiplier = 1;
  
    // Do stuff
}

As you can see, this method has a local variable called costMultiplier and sets the value to 1. But suppose that costMultiplier varies from vehicle to vehicle. In this case, you'd want to pass in this multiplier as a parameter instead of creating it as a local variable. The first of the parameter refactoring functions will do just that. First, right-click on the costMultiplier variable and select the Promote Local Variable to Parameter function. This will take the local variable and add it as a parameter to the method. Here is a look at the modified code:

public void Collision(int costMultiplier, DateTime CrashDate, 
  int Speed, int DamagePct)
{
    // Do stuff
}

You may be thinking that this is not a big deal; it is basically cut and paste. But Visual Studio also goes and looks for any calls to this method and modifies them as well. If you were calling this method before with the following line of code:

Collision(DateTime.Now, 60, 10);

this method call would be changed to the following:

Collision(1, DateTime.Now, 60, 10);

Notice that Visual Studio not only adds the new parameter, but also passes in the value that the local variable was set to as well, saving time and ensuring that existing code continues to work as it did before.

Suppose you decide that you don't need the CrashDate parameter. If you won't be using it in the method, you can remove this parameter using the second of these parameter refactoring functions, called Remove Parameters. First, right-click on the method name and click Remove Parameters in the Refactor menu. You'll be shown the Remove Parameters dialog, which is shown in Figure 2-37.


Figure 2-37. Remove Parameters dialog

In the Remove Parameters dialog, you can select the CrashDate parameter, click Remove, and then click OK. You are then shown a Preview Changes dialog showing the changes that will be made to any calls to this method. After clicking Apply on that screen, those changes will be made. Any calls to this method will have this parameter removed, and the parameter will be removed from the method signature.

Further, suppose you decide that you don't want costMultiplier to be the first parameter, but rather the last parameter. This is where the last of the parameter functions comes in. First, right-click on the method, then choose the Reorder Parameters menu item on the Refactor menu. This will display the Reorder Parameters dialog, which is shown in Figure 2-38.


Figure 2-38. Reorder Parameters dialog

You can then select the costMultiplier parameter, move it down two spots, and click OK. You will again then be shown the Preview Changes dialog. where you can confirm the changes that will be made to any calls to this method. Click Apply, and the order of the parameters will be changed in the method signature and any calls to this method.

The Refactor menu is a great addition to Visual Studio and will make it much easier to refactor code. If you want to learn more about refactoring, the best resources are the book Refactoring (Addison-Wesley) and the companion web site, http://www.refactoring.com.

Want It Now?

Tired of waiting for Visual Studio 2005 or stuck using Visual Studio .NET 2003 for some reason? A number of commercial tools are available that add similar functionality into Visual Studio .NET 2003:

ReSharper

From Jet Brains:

http://www.jetbrains.com/resharper

C# Refactory

From XtremeSimplicity:

http://www.xtreme-simplicity.NET/CSharpRefactory.htm


View catalog information for Visual Studio Hacks

Return to ONDotnet.com.

Copyright © 2009 O'Reilly Media, Inc.