We recommend using Visual Studio 2017
This documentation is archived and is not being maintained.

A Sneak Preview of Visual C# Whidbey

Visual Studio 2005

Microsoft Corporation

November 2003


Language Innovation
Compiler Enhancements
Productivity Enhancements
Debugger Enhancements

Note   This document was developed prior to the product's release to manufacturing, and as such, we cannot guarantee that any details included herein will be exactly the same as those found in the shipping product. The information represents the product at the time this document was published and should be used for planning purposes only. Information is subject to change at any time without prior notice.


The next release of Microsoft Visual Studio®, codenamed "Whidbey," has been significantly improved for C# developers by adding innovative language constructs, new compiler features, dramatically enhanced developer productivity, and an improved debugging experience. In the area of language innovation, the Whidbey release of C# will support generics, iterators, partial types, and anonymous methods. New compiler features for Whidbey enable developers to do things like disable compiler warnings directly in code or verify ECMA/ISO conformance. Whidbey will also include several productivity enhancements include refactoring, code expansions, code formatting, enhanced IntelliSense, and much more. The debugging experience has also been improved with new features like enhanced datatips, debugger visualizers, design-time expression evaluation, and more. This document is a sampling of some of the new capabilities available in Whidbey and we are continuing to add new features that customers want.

Language Innovation


Generics are one of the big language additions to the C# language in Whidbey. Generics in C# allows classes, structs, interfaces, and methods to be parameterized by the types of data they store and manipulate. Generics are useful because many common classes and structs can be parameterized by the types of data being stored and manipulated. These are called generic class declarations and generic struct declarations. Similarly, many interfaces define contracts that can be parameterized by the types of data they handle. These are called generic interface declarations. Methods may also be parameterized by type in order to implement generic algorithms, and these are known as generic methods.

In the example below, we create a Stack generic class declaration where we specify a type parameter, called ItemType, declared in angle brackets after the declaration. Rather than forcing conversions to and from object, instances of the generic Stack class will accept the type for which they are created and store data of that type without conversion. The type parameter ItemType acts as a placeholder until an actual type is specified at use. Note that ItemType is used as the element type for the internal items array, the type for the parameter to the Push method, and the return type for the Pop method:

public class Stack<ItemType>
    private ItemType[ ] items;
    public void Push(ItemType data) {...}
    public ItemType Pop() {...}

When we use the generic class declaration Stack, as in the short example below, we can specify the actual type to be used by the generic class. In this case, we instruct the Stack to use an int type by specifying it as a type argument using the angle notation after the name:

    Stack<int> stack = new Stack<int>();
    int x = stack.Pop();

In so doing, we have created a new constructed type, Stack<int>, for which every ItemType inside the declaration of Stack is replaced with the supplied type argument int. Indeed, when we create our new instance of Stack<int>, the native storage of the items array is now an int[] rather than object[], providing substantial storage efficiency. Additionally, we have eliminated the need to box the int when pushing it onto the stack. Further, when we pop an item off the stack, we no longer need to explicitly cast it to the appropriate type because this particular kind of Stack class natively stores an int in its data structure.

If we wanted to store items other than an int into a Stack, we would have to create a different constructed type from Stack, specifying a new type argument. Suppose we had a simple Customer type and we wanted to use a Stack to store it. To do so, we simply use the Customer class as the type argument to Stack and easily reuse our code:

    Stack<Customer> stack = new Stack<Customer>();
    stack.Push(new Customer());
    Customer c = stack.Pop();

Of course, once we've created a Stack with a Customer type as its type argument, we are now limited to storing only Customer objects (or objects of a class derived from Customer). Generics provide strong typing, meaning we can no longer improperly store an integer into the stack, like so:

    Stack<Customer> stack = new Stack<Customer>();
    stack.Push(new Customer());
    stack.Push(3);               // compile-time error
    Customer c = stack.Pop();    // no cast required

Partial Types

Partial types allow a single type, like a class, to be split into multiple files. The most useful aspect of this feature is for code generators like Visual Studio, which generate code into a different file from user-written code. In this manner, the designer can much more easily parse and regenerate its code without affecting the code that the user has written. For example:

    // Form1Designer.cs
    public partial class Form1: System.Windows.Forms.Form
        // Designer code
        void InitializeComponent() { … }

    // Form1User.cs
    public partial class Form1
        // user code
        void Mouse_Click(object sender, MouseEventArgs e) { … }

Anonymous Methods

Anonymous methods can be thought of as the ability to pass a code block as a parameter. In general, anonymous methods can be placed anywhere that a delegate is expected. The simplest example is something like:

button1.Click += delegate { MessageBox.Show("Click"); };

There are a few things to notice here. First, it's legal to write a method inline. Second, there is no description of either the return type or the method parameters. Third, the keyword delegate is used to offset this construct. The return type isn't listed because the compiler infers it. That is, the compiler knows what is expected (EventHandler), and then checks to see if the anonymous method defined is convertible to that method.

You may notice that in the previous example there were no parameters listed. This is because they weren't needed within the code block. If these parameters were used, then the declaration would look like this:

    button1.Click += delegate(object sender, EventArgs e) 
      { MessageBox.Show(sender.ToString()); };

Notice that both the type and parameter name are given.


Iterators can be thought of as the logical counterpart to the foreach statement in C#, in that iterators simplify the process of iterating through a collection. Currently, it's very easy to iterate over collections using the foreach keyword. However, writing a collection that is foreach enabled requires the implementation of the IEnumerable and IEnumerator interfaces, as well as the creation of a separate Enumerator class/struct. Iterators alleviate the work of writing this boilerplate code and make it easier for framework developers to expose enumerable collections. For example:

    class List<T>: IEnumerable<T>
        private T[] elements;
        public IEnumerator<T> GetEnumerator()
            foreach (T element in elements)
                yield element;

You'll notice above the use of the newly introduced keyword yield. yield can only be used in methods that return IEnumerator, IEnumerable, or their generic equivalents. Iterators can also be named and passed as parameters, however, in most cases named iterators will return IEnumerable instead of IEnumerator. For example:

    class List<T>
        private T[ ] elements;
        public IEnumerable<T> Range(int from, int to)
            while (from < to) yield elements[from++];

Alias Qualifier (Global Namespace Qualifier)

One of the problems that code generators face today is making sure not to interfere with any code that has either been written by the user, or created by a code-generation tool like Visual Studio. As a general practice, we encourage generators to always fully qualify the types that they emit. However, there is one issue with fully qualifying a type in C# in that it's not possible to search for types at the root namespace. The global namespace qualifier solves this problem by introducing the "::" operator, which can be used as a namespace or type name prefix. This lets developers explicitly reference the root namespace within code, as shown below.

namespace Acme
  namespace System
    class Example
          static void Main()
            // In Visual Studio 2003, looking up  
            //  System.Console.WriteLine would have
            // started in the Acme.System namespace.

Static Classes

Static classes are meant to replace the design pattern of creating a sealed class with a private constructor that contains only static methods. A static class is denoted by placing the static modifier on the class declaration. For example:

    public sealed class Environment 
      // Keep class from being created
      private Environment() { }

can now be written as:

    public static sealed class Environment

The benefit of using a static class instead of the design pattern above is that the compiler can now report an error if any instance methods are accidentally declared.

Compiler Enhancements

Inline Warning Control

Another new feature for Whidbey is the ability to control whether warnings are reported for a particular region of code by specifying a compiler directive. This directive takes the familiar form of a #pragma statement. Below is an example that uses the pragma keyword to disable a compiler error for a particular block of code.

    #pragma warning disable 135
        // Disable warning CS135 in this block
    #pragma warning restore 135

Command Line Options

Whidbey includes several new compiler options. A short description of each of the new options follows:

  • /warnaserror: The warnaserror command line option in Visual Studio .NET 2003 enabled developers to treat all compiler warnings as errors. In Whidbey this feature has been extended to enable developers to control whether specific warnings should be treated as errors. The example below shows how you can mark all warnings as errors except warning 618.
         csc /warnaserror /warnaserror-:618 ...

    Alternatively, you can mark a single warning as an error as shown in the example below:

               csc "/warnaserror:1595 ...
  • /errorreport:<string>: The errorreport command line option controls Dr. Watson reporting for the compiler. For more information on Dr. Watson, please visit http://www.microsoft.com/technet/prodtechnol/winxppro/proddocs/drwatson_setup.asp. The possible parameters available for the errorreport option are listed below:
    • /errorreport:prompt: This option displays a dialog box with information about the error.
    • /errorreport:send: This option indicates that if the compiler encounters an internal error it should not prompt the user with a modal dialog box. However, it should still compile and send the error report. The same text that would appear in the dialog box is instead written to the command line.
    • /errorreport:none: This option indicates that no information should be sent to Microsoft about the error. This is the same behavior as Visual Studio 2002 and Visual Studio 2003, and is the default option.
  • /langversion:<string>: The langversion command line option's main purpose is to enable strict ECMA/ISO conformance. With this option set to ISO-1, the compiler will report errors for all features introduced in Whidbey that aren't part of the standard.
  • /keycontainer, /keyfile, /delaysign: These options will be used to replace the attributes of the same name for more flexibility in assigning command line arguments.

Productivity Enhancements


The C# Whidbey IDE now includes refactoring support. Refactoring enables developers to automate many of the common tasks when restructuring code. For more information on refactoring, please visit http://www.refactoring.com/. Using the built-in refactoring support, developers can, for example, use the rename refactoring to automate the process of renaming a variable in source code.

The refactorings currently available in the Whidbey Technical Preview are:

  • Extract Method
  • Rename
  • Extract Interface
  • Encapsulate Field
  • Change Method Signature
  • Replace Arraylist

The figure below shows how the refactoring features can be utilized directly from the context menu inside the code editor.


Figure 1. Refactor menu

When Rename refactoring is invoked, the user sees the Preview Changes dialog box. This dialog lists any places in either the comments or code where the variable name is used. The context menu in the Preview Changes dialog box also lets users jump directly to the line of source code referencing the variable.


Figure 2. Preview Changes for the Rename refactoring


Expansions, which are fill-in-the-blank" snippets of code, help reduce the number of keystrokes for repetitive tasks and simplify adding common constructs like the foreach statement to your application. Developers can access expansions by accessing the context menu and selecting expansions, or by directly invoking the configurable shortcut key for expansions.


Figure 3. Expansions

The example below shows a code expansion that uses the "forr" expansion to traverse a collection in reverse order. The cursor is placed on the highlighted yellow text areas, which act as placeholders for user values. In the example below, the "forr" expansion loops through every element in the myList generic collection in reverse order.


Figure 4. forr Expansion

Expansions are fully extensible XML files that can be customized or created by users.


Figure 5. XML format for the "forr" expansion


Source code formatting is always a matter of personal preference, and Visual Studio Whidbey includes several options to fully customize and control how your source code is formatted. These formatting options include braces, spacing, indentation, wrapping, and alignment. You also have the choice of having the IDE format code automatically, or just a particular section of source code. Figure 6 below shows the formatting new line options for braces as well as a visual preview of the selected formatting option.


Figure 6. Formatting options and preview pane


While developers enjoy the ability to fully customize the IDE's fonts, windows, and formatting, sharing your settings with other team members or transferring your settings to another machine is a difficult process. Whidbey adds the ability to easily import and export your IDE settings between machines or share them with team members.


Figure 7. Import/Export settings dialog

Enhanced IntelliSense

IntelliSense has been enhanced to understand generic types. In the figure below, IntelliSense understands that myList represents a list of integers and provides a pop-up describing that the Add method of myList is expecting an integer data type.


Figure 8. Intellisense understands generics

IntelliSense has also been enhanced for exceptions. When adding a try/catch block, the catch handler intelligently filters the available options to only show a list of exception types.


Figure 9. IntelliSense for exceptions

IntelliSense has also been enhanced for attributes. In the example below, adding an attribute filters the available options to only show a list of attribute types.


Figure 10. IntelliSense for attributes

User Type and Keyword Coloring

When reviewing source code, one of the easiest ways to distinguishing between types and keywords is by coloring them differently in the IDE. Whidbey introduces the ability to uniquely color user types and user keywords for easier source code readability.


Figure 11. Different user type and keyword coloring

New Build System

The build system for Whidbey has been greatly improved. The new build system, named MSBuild, uses an extensible mechanism to describe how a build happens. Users can create their own build system using custom tasks written in XML. The example below shows a simple MSBuild file with a compile task that invokes the C# compiler for any file that ends with the ".cs" extension.

- <Project>
    <Item Type="Compile" Include="*.cs" /> 
 - <Target Name="Build">
      <Task Name="Csc" Sources="@(Compile)" /> 

Find searches hidden text by default

A common request we received for the Find and Replace window was to change the default behavior so that collapsed text, like the text inside a region, is searched by default. In Visual Studio 2003 this behavior is off by default, while Whidbey turns searching hidden text on by default.


Figure 12. Searching hidden text in the find and replace dialog

Object Browser Improvements

While developers commonly used the object browser for inspecting data types, many wished that it would add the ability to filter results. The Whidbey object browser now lets developers filter and sort data by namespace, object type, alphabetically, and more.


Figure 13. Object browser improvements

Easier Window Docking

To make docking windows easier in the IDE, we now provide you with a set of transparent guides, which you can hover over to dock windows to the left, right, or bottom of the IDE.


Figure 14. Docking windows

Auto Save in the IDE

To prevent loss of information due to inadvertently closing unsaved file changes for example, the IDE now auto saves your work on a regular basis and should the IDE crash, it will prompt you to recover your work when you restart.


Figure 15. Auto saving files

Change Tracking

Change tracking makes it easy to visualize the differences between saved and unsaved code.

In the figure below, you'll notice that the far left pane is colored differently for certain sections of code. The code highlighted in yellow represents new code that has not yet been saved, while the code highlighted in green represents new code that has been saved. Code that is neither yellow nor green represents code that existed when the file was originally opened.


Figure 16. Change tracking

New Windows Forms Controls

Windows Forms for Whidbey adds several new controls ranging from improved data controls like the GridView, to new controls like the Sound control for audio, and the Winbar control for customizable menus.


Figure 17. Winbar Control

New Web Form Controls

ASP.NET has several new enhancements to dramatically improve developer productivity. Several of these features are available in new ASP.NET control categories, like Personalization, Security, Validation, and Navigation. For a full list of Visual Studio enhancements for Web developers, visit http://msdn.microsoft.com/asp.net/whidbey/.

Control Alignment

Aligning controls in the designer is much easier in Whidbey. In the example below, when a user drags button 2, a set of alignment lines appear to visually show how Button 1 is aligned with button 2.


Figure 18. Aligning controls

Smart Tags for Controls

Smart Tags have been added for controls that show the common tasks associated with that control, like formatting and connecting to a datasource.


Figure 19. Smart tags on controls

Quicker Web Projects

To create Web projects for Whidbey, you no longer need to have IIS installed. Simply select a site to create and Visual Studio will allow you to create a website on a fileshare that you can run and debug locally.

SQL Server 2005 Project Support

Visual Studio Whidbey also includes support for building applications for the next version of SQL Server, SQL Server 2005.


Figure 20. Creating a SQL Server 2005 Project

Debugger Enhancements

Enhanced Datatips

While in debug mode using Visual Studio .NET 2003, you can place the cursor over a simple variable like a string to inspect its value. In Whidbey this has been greatly enhanced to handle much more complex types. In the figure below, the Datatips show information about a complex type and also includes the ability to drill into the hierarchy for that type.


Figure 21. Enhanced Datatips


In Visual Studio .NET 2003, there wasn't a simple way to see complex types like Datasets, bitmaps, and so forth directly in the debugger. Visualizers are a way to visually represent data while in debug mode. For example, you can visualize the contents of an XML string by selecting the XML visualizer directly from the Autos window as shown in the figure below. Visualizers are also fully extensible so developers and component providers can create custom visualizations for their own types.


Figure 22. Visualizer options


Figure 23. XML visualizer

New Symbol Server Options

If you wanted to use a symbol server in Visual Studio 2003, you had to setup a system environment variable like:


And this could only be done before debugging. In Whidbey, we have made it easy to setup multiple symbol server locations and set the path to your local symbol cache. You can also setup up your symbol server after you are in break mode, which can be useful when you realize the debug symbols have not yet been loaded.


Figure 24. Symbol server options

Design Time Expression Evaluation

In Whidbey, the Immediate window can now be used to evaluate expressions at design time without having to compile and run the application. In the example below, the Add method is called directly from the immediate window without having to leave the design time environment.


Figure 25. Evaluating methods in the immediate window at design time

Configurable Security Permissions

Whidbey simplifies testing different security credentials by enabling developers to debug their applications with configurable security permissions.


Figure 26. Configurable Security Permissions


Visual Studio Whidbey builds on the success of Visual Studio 2002 and Visual Studio 2003 to make developers even more productive then ever before. With the new language constructs, compiler features, productivity enhancements, and debugger improvements, developers will be able to create more powerful applications in less time and focus on writing code.