A Sneak Preview of Visual C# Whidbey
Microsoft Corporation
November 2003
Contents
Introduction
Language Innovation
Compiler Enhancements
Productivity Enhancements
Debugger Enhancements
Summary
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.
Introduction
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
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>();
stack.Push(3);
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
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.
::System.Console.WriteLine("Hello");
}
}
}
}
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
Refactoring
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
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
Formatting
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
Profiles
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)" />
</Target>
</Project>
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
Visualizers
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:
_NT_SYMBOL_PATH=srv*E:\Cache\Symbols*http://msdn.microsoft.com/downlo
ad/symbols;
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
Summary
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