I haven’t had a chance to post much recently, but I ran into a nice mail on an internal alias that listed the restrictions of set next statement. Set next statement is a very powerful feature of the debugger that allows the IP (instruction pointer) to be moved. It’s particularly useful when combined with Edit and Continue. This feature can be accessed from the context menu of the editor when the debugger is active. It may also be accessed by simply dragging the yellow arrow that appears on the left hand side of the screen while debugging. There are a number of restrictions associated with changing the IP including:
· It can only be set within the same function/method
· There are restrictions around setting it into or out of a catch block (exception handler)
· It must usually be moved to source lines
· The IP cannot be set when the debugger is stopped at a first chance exception
· The IP can only be set in the active frame (the frame that is actually executing). That is, you cannot go 6 frames up the call stack and try to change the return address.
The most important thing to understand about this feature is that there is no real magic going on. It does a very minimal amount of work to move the IP; it does not try to change values back to their previous state if the IP is moved higher up in a method. If you’re tracking down a bug in your application, it’s often useful to step over most methods until something unexpected happens (e.g. a return value isn’t what you expect). You can then use set next statement to re-run the method but this time step into it and examine what went wrong. This can help track down bugs much faster, and of course, with Edit and Continue you can often fix the problem and then re-run the offending block of code to see if the change worked.
Imagine that you have this simple, somewhat useless bit of code:
using System;
class Example
{
static void Main(string[] args)
{
int initialValue = 20;
initialValue++;
Console.WriteLine(initialValue);
}
}
Let’s suppose that you’re debugging this and your IP is located on Console.WriteLine:
Now you right-click on the source line containing initialValue++ and select “Set Next Statement”:

Finally you hit F5 to finish running the application. The value written to the console is 22, not 21. Again, this is because Set Next Statement doesn’t perform any kind of state analysis, it simply moves the IP to the location indicated. In this case, it’s possible to get the original behavior by simply moving the IP up to the source line that sets the value of initialValue. That’s trivial in this case since the initial assignment is immediately above the modification. If there is a significant amount of code that you don’t want to re-run, then you can also modify the value in the locals/watch/etc. windows instead.
Extern aliases is a feature that was introduced in VS 2005 that I don’t believe is being used very often. There are two reasons for this. First, the feature is somewhat undiscoverable, particularly if you don’t happen to be looking for it. Second, the feature itself is useful in the somewhat narrow scenario of needing to explicitly differentiate between two type names that are identical except for the assembly strong name (name, version, public key, etc.) in which they are defined.
Of course, if you happen to be in that situation this feature can prove invaluable.
I wrote the walkthrough below while we were developing the feature; it should provide a reasonable starting point for how extern aliases can be used in Visual C#.
- Create a C# Class Library called FooVersion1
- Replace the template code in Class1.cs with the following:
using System;
namespace Acme
{
public class Foo
{
public void Bar()
{
Console.WriteLine("Bar");
}
}
}
- Right-click on the solution in solution explorer and select Add | New Project
- Save the current project (only applicable in express)
- Select a Class Library in the new project dialog and change the project name to FooVersion2 and press OK
- Replace the code in Class1.cs with the following:
using System;
namespace Acme
{
public class Foo
{
public void Bar()
{
Console.WriteLine("Bar");
}
public void Goo()
{
Console.WriteLine("Goo");
}
}
}
- Right-click on the solution in solution explorer and select Add | New Project
- Select a Console Application and call it Consumer
- Right-click on Consumer and select ‘Set as startup project’
- Right-click on the references node in the Consumer project and select ‘Add Reference’
- Click on the projects tab, and multi-select FooVersion1 and FooVersion2
- Click OK
- Add the following line to Main in the Program type of the Consumer project:
Acme.Foo f = new Acme.Foo();
- Build the solution via Ctrl+Shift+B (or F6)
- Notice that you get two build errors:
- Open solution explorer and select FooVersion1 in the References folder of the Consumer project
- Hit F4 (or select View | Properties Window)
- Change the Aliases property to FooVersion1
- Build the solution
- Now everything will build correctly, because Acme.Foo unambiguously refers to FooVersion2
- Add the following directive to the top of Program.cs in the Consumer project:
extern alias FooVersion1;
- Change the usage of Acme.Foo to:
FooVersion1::Acme.Foo f = new FooVersion1::Acme.Foo();
f.Bar();
- Notice that when you type ‘f.’ the completion list contains only those methods in FooVersion1 of Acme.Foo (notably it does not include Goo)
- Build the solution and everything will build correctly
- Finally add the following code under f.Bar() in Program.cs of the Consumer project:
Acme.Foo f2 = new Acme.Foo();
f2.Goo();
- Notice that f2’s completion list contains Goo.
- Build again using Ctrl+Shift+B and notice that there are still no build errors
This shows a usage pattern which we expect to be relatively common when these ambiguities exist. The assembly which will be used less often will be aliased while the other will continue to exist in the global namespace (such that it doesn’t require qualification through an extern alias).
A recent post in the Visual C# IDE forum (seems like I start a lot of blogs this way J) got me thinking about function evaluation (“FuncEval”) while debugging. I don’t think there is any scarier term for a debugger developer – seriously, I’ve seen them cower in fear. FuncEval is, quite simply, the process of invoking a method while stopped in the debugger. This feature is invaluable for managed code debugging for a number of reasons; chief among them, however, is the very simple desire to see the value of properties in the various data windows. Keep in mind that underlying a property are the getter and setter methods. FuncEval not only enables property evaluation, but also features like debugger visualizers, design time expression evaluation (and expression evaluation in general), the object test bench and many others that make the managed world a fun place to be.
So, why would a debugger developer hide whimpering in a corner every time a new feature based on FuncEval is introduced? The Visual Studio debugger is designed to allow deep inspection of data at a given point of time in an application’s execution. That ‘point in time’ can be hit via a breakpoint, stepping, an exception being thrown, etc. Now, let’s suppose that the problem is an exception. The debugger may stop the program at the point where the exception is unhandled, enters user code, is thrown – generally good places to understand what the problem is. The point is at that moment in time the state of the program is such that an exceptional situation occurred and the debugger’s job is to give the developer enough information about the state to find out how to prevent it in the future. The problem is that function evaluations can modify that state. This is often referred to as a side effect of the evaluation though, in truth, it could easily be the desired behavior of the evaluation and only a side effect when evaluated in the debugger. An example will probably clarify this a bit:
Run this program under the debugger. An exception is thrown in BehavingBadly.DoSomething because handle is null. Let’s suppose that the first thing that the developer does is to open up the locals window and expand ‘this’ to examine the state of the object. At that point, the Handle property is executed, it sees that the field is set to null, and subsequently allocates a new Handle for it. This could clearly be confusing – a NullReferenceException, but handle is clearly assigned a value!
It turns out that it’s even more insidious. Function evaluations are order dependent. If an ‘implicit’ function evaluation, like a property, changes state that another field depends on then the value shown in the debugger may not actually reflect the current value of the field. For example:
Set a breakpoint on the closing brace of Main and start debugging. Examine p in the watch window. Notice that the debugger says that the current value of p.a is 0. Type p.a in the watch window. It now says the value of p.a is 1. This becomes even more interesting from a UI perspective because you may have multiple windows showing the same data (like the locals and watch in this example). In that case, should the property be called twice, or should the debugger attempt to cache the value and show that? How long does the value stay cached for – what if there is an explicit call, say, in the immediate window that affects its value? The debugger currently reevaluates properties for different views (in VS 2003 a single view, like the watch window, could actually cause a property to be evaluated many times).
I’m sure it’s becoming clear why debugger developers aren’t huge fans of implicit function evaluation (that is, function evaluation that happens without an explicit user action). It turns out that there is even more bad news. Function evaluation is slow, hundreds of times slower than simply examining a field. It’s also not guaranteed to finish executing; a property evaluation may simply spin forever. Therefore the debugger imposes a 10 second timeout at which point it attempts to abort the function evaluation. The CLR can’t actually guarantee much about function evaluation aborts, so it’s not an operation we want to happen very often. In addition, function evaluation runs in the debuggee itself (which is how it modifies the debuggee’s state). That means that when a function evaluation is occurring the debugee has an active thread. This can cause difficult to understand and debug problems, particularly in multi-threaded applications.
It may seem like I’m making a case for eliminating FuncEval (or at least implicit FuncEval) entirely. On the contrary, I’m as much to blame as anyone for the increased usage of implicit FuncEval in C# debugging in VS 2005. In VS 2005 I was the PM for the expression evaluator, which is the part of the debugger that understands a particular language (such that it’s possible to evaluate arbitrary expressions like 1+Foo() in the immediate and watch windows). A number of the features that improve data visualization require function evaluation to work. For example, the VS 2005 C# debugger will implicitly call ToString on objects that are displayed in the debugger variable windows. This often gives a significantly better immediate view of the data. Debugger visualizers and type proxies, extensible systems for providing your own data visualization also require function evaluation. Type proxies are used to greatly enhance the display for collection types like Dictionary<T> (where the underlying store isn’t even close to the client’s conceptual model).
The trick of course is to harness the power of function evaluation in such a way that for the vast majority of cases it makes it easier to debug a program instead of harder. That’s why we try to limit the number of places that we perform implicit function evaluations to methods that should not have side effects. Property evaluations are very often safe to call because a large number simply return the underlying field. ToString methods should virtually never modify the state of the object.
I’ve got a lot more to say on the subject, including common examples of performance problems that may be introduced by function evaluations, customization options, workarounds for situations where better data visualization is important but you can’t use ToString, when function evaluation doesn’t work, and of course a more convincing explanation as to why implicit function evaluation is a good thing. Unfortunately I’m exhausted so it’ll have to wait for another day…
Ever since we released the first version of C# 1.0 I’ve received a question or two a month about XML documentation comments. These are often referred to as ‘doc comments’ for short. The questions range from the use of doc comments in VS to the recommended schema of the XML. This post captures a few of the common questions that I’ve seen.
Why isn’t there a multi-line version of XML doc comments?
There are actually two forms of doc comments in C#, single and multi-line. However, the single-line version is by far the most commonly used; in fact, the multi-line version wasn’t supported until the 1.1 version of the compiler even though they were defined in the 1.0 version of the language spec. The single line version is likely to be familiar to any user of Visual Studio; it’s syntactically indicated on a line that starts with a triple slash (///):
/// <summary>
/// This is the single line version of the doc comment
/// </summary>
static void Example()
{
}
The multi-line version uses /**:
/** <summary>
* This is the multi-line version
* </summary> */
static void Example()
{
}
They are functionally identical, the only difference being that it’s possible to use the multi-line version “inline” within an expression. The multi-line version of the comments weren’t actually in the proposed version of the language specification submitted to ECMA; however, the ECMA committee decided that having both forms would be better.
The C# language service doesn’t support multi-line XML doc comments as well as the singe line comments (i.e. /** doesn’t auto-generate any tags); however, colorization for multi-line doc comments does work, and in VS 2005 it’s possible to get completion lists for the tags but you must first end the multi-line comment and then go back and enter in the tags.
How do I make VS show the XML doc comments of the types and methods of my components in completion lists and object browser?
This has been an extremely common question for a long time. The short and long of it is that you must deploy the XML file that is generated by the compiler with the component. They must be in the same directory, and the XML file must have the same name as the component except with an .xml extension. I wrote a whitepaper that contains a walkthrough, in VS 2003, which demonstrates this. It’s available here.
How do use XML doc comments to refer to generic types?
Several of the tags that are recommended in the C# language specification have an attribute named ‘cref’ on them. Cref refers to a code reference. This attribute can be used by tools to create links between different types and members (e.g. object browser uses crefs to create hyperlinks that allow quick navigation to the related type). The C# compiler actually understands the cref attribute to a limited extent. The compiler will try to bind the type or member listed in a cref attribute to a code element defined your source. Assuming that it can it will then fully qualify that member in the generated XML file. For example:
using System.Collections;
class Program
{
/// <summary>
/// DoSomething takes a <see cref="ArrayList"/>
/// </summary>
void DoSomething(ArrayList al) { }
}
This generates the following XML file:
<member name="M:Program.DoSomething(System.Collections.ArrayList)">
<summary>
DoSomething takes a <see cref="T:System.Collections.ArrayList"/>
</summary>
</member>
Notice that the compiler bound ArrayList and emitted System.Collections.ArrayList instead.
I’m sure you’re saying, wow, fascinating, um… but what does that have to do with generics? Good question. Generics complicate doc comments because C# uses angle brackets which would usually be associated with XML. It’s possible just to use the normal escaping mechanisms associated with angle brackets (> <) in XML. Unfortunately this turns out to look fairly ugly:
using System.Collections.Generic;
class Program
{
/// <summary>
/// DoSomething takes a <see cref="List<T>"/>
/// </summary>
void DoSomething(List<int> al) { }
}
This can become particularly onerous when the generic type has many type arguments. The compiler team decided to improve this by allowing an alternate syntax to refer to generic types and methods in doc comments. Specifically, instead of using the open and close angle-brackets it’s legal to use the open and close curly braces. The example above would then become:
using System.Collections.Generic;
class Program
{
/// <summary>
/// DoSomething takes a <see cref="List{T}"/>
/// </summary>
void DoSomething(List<int> al) { }
}
The compiler understands this syntax and will correctly bind List{T} to System.Collections.Generic.List<T>.
When the <example> tag is used and there are a number of generic types or methods in the example, an easier approach is to simply surround the example with a CDATA block. That way there is no need to escape less-than signs.
Which doc comment tags are understood and used by Visual Studio?
There are a number of tags that Visual Studio uses to process or present information:
|
Tag name |
Tools that make use of the tag |
|
summary |
Completion lists, quick info, class view, class designer, object browser, object test bench |
|
param |
Parameter help, quick info, object test bench, class designer, object browser |
|
exception |
Completion lists, quick info, object browser |
|
include |
C# Compiler |
|
returns |
Object browser |
|
see/seealso |
Object browser |
The ‘metadata as source’ feature, which is invoked when goto definition is performed on a type or member that is defined in metadata, processes a number of the tags documented in the C# language specification and tries to provide a reasonable view.
How do I generate HTML or .chm documentation from the XML file?
The generated XML file actually doesn’t contain enough information to fully generate good reference documentation. In fact, it was an explicit goal to make the XML file contain just enough information to map the comment back to the associated code element in metadata. Regardless, there are a number of tools that take the assembly and the generated XML file and produce a very nice looking, easy to browse output. NDoc has been a favorite of many developers that I’ve talked to for quite a while. I believe that development on NDoc has slowed somewhat; another option is SandCastle.
There was a recent post in the Visual C# IDE forum which started me thinking about navigating through a solution in Visual Studio. The post was basically asking whether it’s possible to quickly navigate to a file in your solution if you know its name. There are a few different navigational approaches that Visual Studio offers. First, if the file is already open, then it’s possible to use Ctrl+Tab or the tab channel to find the file. Ctrl+Tab functionality was actually significantly improved in VS 2005. In VS 2003 Ctrl-Tab had no UI associated with it, so it was difficult to navigate to a particular open file (though it was extremely good at quickly switching between 2 or 3 files). In VS 2005 Ctrl+Tab now shows UI that enables navigation to both open files and active tool windows. The UI is modeled after the Alt-Tab functionality in Windows:
It’s not immediately obvious the first time that the Ctrl+Tab feature is used that the arrow keys can be used to navigate among the items. For example, invoke the window by typing Ctrl+Tab. Keep the Ctrl key depressed, but release the Tab key. Now simply use the arrow keys on the keyboard to change the selection to either the file or tool window that should acquire focus.
Another option to quickly navigate to open files is the use of the file tab channel. The tab channel (the list of tabs that contain the name of the documents that are open if ‘tabbed documents’ is the current mode) also underwent an overhaul in VS 2005. The mouse is an obvious way to navigate using the channel, but there is a more keyboard focused route as well. The channel has a little chevron on the right hand side which when clicked will show a drop-down of all open documents (regardless of whether they are visible in the tab channel). This shortcut can be invoked via Ctrl+Alt+<Down Arrow>. A small drop-down appears and has focus; the arrow keys can be used to quickly select the file to make active:
The final tried and true mechanism that I’ll talk about for accessing open documents is the Windows ‘window’. It’s accessible off of the Window top level menu item (Alt-W, W). This particular navigation mechanism is useful to know because it works the same in VS 2003 and VS 2005, and it works regardless of whether environment is set to ‘tabbed documents’ or ‘multiple documents’. The accelerator key for activating the selection is “Alt+A” when the window has focus:
Of course, none of those navigation methods works if the desired file isn’t already open in the editor. There are several different ways to navigate to open a file, but the most common is probably Solution Explorer. In fact, the question referenced above was specifically about finding a way to navigate solution explorer via the keyboard (quickly) even in the face of collapsed nodes. It turns out that there really isn’t a good way to do this. However, there are a few other options for opening files that are in the solution. For example, it’s possible to quickly open a file in the solution using the find combo box that appears on the Standard toolbar. The keybinding to jump to the combo box is Ctrl+/ with the C# keybindings. Invoke this keybinding, and then type “>” to enter ‘command’ mode. Type the word ‘open’ and then start to type the name of a file in the solution. A list of files, filtered by the text already typed, appears as a dropdown:
The biggest problem with this approach is that selecting an item in the list immediately puts the full path name of that item into the combobox, which after another character is typed (like backspace) will filter the list down to only files with that path. A smaller issue is that the list also contains various other solution artifacts like the references, so the list is longer than it needs to be. The nail in the coffin for me is that it doesn’t filter based on substrings anywhere in the filename, but rather only what the filename starts with. That is, searching for Item wouldn’t return “IconicItem.cs.”
I’ve often found myself wanting a way to quickly navigate to a file that meets the following requirements:
· A modal UI that disappears as soon as I’m done using it
· A filtered list of only the files that are in my solution
· A way to quickly search through those files using a substring search
· Keyboard focused access such that I don’t need to use the mouse at all
It turns out that Visual Studio doesn’t have a tool or feature that meets all of these criteria by default. There are many that come close, like the Find Combo above, or Open File (Ctrl+O). Unfortunately none of them is exactly what I want. Luckily it’s possible to extend VS with some interesting addins. In this case I wrote a simple little navigation tool that has the following UI:
The Matching Files listbox contains all of the files in the solution, regardless of their project (or their type, notice NavigationForm.resX). The Project listbox is contextual based on the selection in the Matching Files listbox. In this case AssemblyInfo.cs occurs in the NavigationUI, FileNavigationAddin, and TypeNavigationAddIn projects. The ‘Select a file to Open’ textbox filters the list of Matching Files down based on a substring match. The up and down arrows will change the selection in the Matching Files listbox even while the ‘Select a file to open’ textbox has focus; similarly, the Shift+ the up or down arrows will change the selection in the Project listbox.
The addin works fairly well for small to medium solutions, but it takes time to appear in the face of larger solutions. Currently it enumerates the files in every project in the solution every time it is invoked. To make it faster would require keeping track of a list of files and updating them based on project events like additions, removals and renames, which I haven’t been motivated to do yet.
Regardless, the file navigation addin is available here in .vsi form (open the zip file and double-click on the .vsi). After running the VSI a new command named FileNavigationAddin.Connection.Connect.FileNavigationAddIn is added to Visual Studio. There is no default keybinding, so one must be set through the Tools | Options | Keyboard page. I override Ctrl+T because I never use Edit.TransposeCharacter.
There was an interesting post a while back in the Visual C# IDE forum asking whether or not it was possible to automatically insert company specific information every time that a new file is added to a C# project (specifically in C# Express 2005). It turns out that it is possible. The idea is to create a new item template that contains this information by default. Item templates are the name of the elements that appear in the "Add New Item..." dialog. This dialog appears when a project is right-clicked and Add New Item... is selected.
In order to illustrate this, let's take a look at two possibilities for creating a template which adds a new class. Item templates are stored in zip files. The set that are installed by default for C# Express are located at Program Files\Microsoft Visual Studio 8\Common7\IDE\VCSExpress\ItemTemplates\1033. Copy the Class.zip file, which represents the class item template, to My Documents\Visual Studio 2005\Templates\Item Templates\Visual C#\. The .zip file contains two files, a .vstemplate file and a .cs file. The .vstemplate file controls a number of the display attributes that are shown in the Add New Item dialog, such as the name of the template, the icon, the description, etc. It also contains all of the information that the project system uses to figure out which files this item template adds to the project. It is a fairly straightforward XML format. In this case, let's modify the name slightly so it's clear that the template has been added. That requires changing the line in the .vstemplate file from:
<Name Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}"