Visual Studio .NET provides a new set of features designed to improve and enhance the development experience.

Most of these changes have to do with user ergonomics and are typical of a minor release of a Visual Studio product. Only a few of the changes are related to the underlying platform. This article assumes you are familiar with Visual Studio .NET 1.0 and it presents only the new features of the IDE (Integrated Development Environment) of Visual Studio .NET 1.1, for both C# and Visual Basic .NET. J# is not discussed because it was not part of Visual Studio .NET 1.0. In the interest of space, some minor cosmetic changes (such as reorganization of the Start page) are not listed.

IntelliSense Enhancements

IntelliSense gets a boost with Visual Studio .NET 1.1, with many new features and capabilities. These features are clearly aimed at automating mundane programming tasks and have nothing to do with the new .NET 1.1 runtime.

IntelliSense History

Visual Studio .NET 1.1 keeps track of the most frequently used methods or properties of any type you interact with during code writing. When you type the dot (".") character to de-reference a type member, IntelliSense will suggest the member you are most likely to choose based on your history of using this type. If you start typing the member prefix, IntelliSense will refine its suggestion but still base it on history. For example, consider the Trace class, defined in the System.Diagnostics namespace. The Trace class is used to trace some information using the WriteLine() static method:

Trace.WriteLine("I am here");

WriteLine() writes the content of the trace message to the Output window and appends a new line feed. The Trace class has a method called Write() that does not append the line feed, so you are far less likely to use it. In Visual Studio .NET 1.0, if you were to type "Trace.w" then IntelliSense would suggest Write() instead of WriteLine(), because it is first alphabetically. In Visual Studio .NET 1.1, if you use WriteLine() more frequently that you use Write(), then IntelliSense will suggest WriteLine() instead (see Figure 1).

Figure 1: History-based IntelliSense. In C#, IntelliSense will use both the prefix of the member and the history of the most frequently used members to suggest a type member.

If you only type the dot, IntelliSense will suggest the most frequently used member of the type. IntelliSense history works both for Visual Basic .NET and for C#. However, C# developers can configure IntelliSense to use alphabetical order instead of most used history. You will see how to do just that later on in the section about the Tools options.

Skeletal Interface Implementation

As a developer, you will occasionally need to implement a class based on an interface defined by another party. Instead of copying and pasting the interface definition or typing it in, you can use Visual Studio .NET to generate a skeletal implementation of an interface in your class. A skeletal implementation is a do-nothing implementation of the interface: methods do not modify parameters and they return default values. A skeletal implementation is required to at least get the code compiled as a starting point when implementing an interface. To have Visual Studio .NET generate a skeletal interface implementation, first add the interface to the class derivation chain. When you finish typing the interface name (such as IFoo), IntelliSense will ask in a tool tip: "Press TAB to implement stubs for interface 'IFoo'." (see Figure 2).

Figure 2: When adding an interface to a type derivation list, you can press Tab to have IntelliSense implement a skeletal interface implementation.
IntelliSense will suggest the member you are most likely to choose, based on your history of using this type

If you press the Tab key, Visual Studio .NET will create a skeletal implementation of the interface on your class, and will scope it with a collapsible #region. For example, for this interface definition:


public interface IFoo
{
   void Method1();
   bool Method2(string str);
}


Visual Studio .NET will generate this skeletal implementation:

public class MyClass : IFoo
{
   #region Implementation of IFoo
   public void Method1()
   {
   }

   public bool Method2(string str)
   {
      return true;
   }
   #endregion
}

The skeleton returns a default value from methods that have a return value so that you can compile it. In Visual Basic .NET, when you add the Implements directive and supply the interface name, Visual Studio .NET will automatically add the skeletal interface implementation. For example, for this interface definition:

Public Interface IFoo
   Sub Method1()
   Function Method2(ByVal str As String) As
      Boolean
End Interface

Visual Studio .NET will generate this skeletal implementation:

Public Class SomeClass
   Implements IFoo

   Public Sub Method1() Implements IFoo.Method1

   End Sub
   Public Function Method2(ByVal str As String)
      As Boolean Implements IFoo.Method2
   End Function
End Class

C# Automatic Event Hookup and Handler Generation

.NET delegate-based events are a type safe way to connect an event publisher to an event subscriber. Because the exact signature of the event handling method is known, IntelliSense can generate the code creating a new delegate object targeting the event handling method, and even the event handling method itself.

For example, consider the MyPublisher class, which is used to publish events to interested subscribers about changes to the value of some number:

public delegate void NumberChanged(int num);

public class MyPublisher
{
   public event NumberChanged NumberChanged;
   /* Other methods and members */
}

Suppose the class MySubscriber wants to subscribe to the event in the class constructor. When you type the += operator to assign into a delegate, IntelliSense will preset a ToolTip offering to add a new delegate of a matching type by pressing the Tab key. If you do not like the default target method name you can simply type a different method name in its place. If the target method does not exist, IntelliSense will offer to generate a handling method by that name by pressing the Tab key once more. This sequence is presented in Figure 3. This IntelliSense support only works with delegates defined as events (not mere delegates). Also worth mentioning is that there is no IntelliSense support for removing a subscription:

public void UnSubscribe()
{
   //This has no IntelliSense support:
   publisher.NumberChanged -= new
   NumberChanged(OnNumberChnaged);
}

Figure 3: C# Auto Event Hookup and Handler Generation. When adding a new delegate to an event invocation list, IntelliSense can auto-insert the delegate instantiation, and even generate the code for the event handling method.

C# Overriding Method Auto-Completion

When you type the reserved word Override, IntelliSense lists all the override-able methods of the type, including its base classes. Once you select a method, IntelliSense will insert an implementation that calls the base class. For example, in a Windows Forms Form-derived class, if you select to override the WndProc method, IntelliSense will generate this code:

protected override void WndProc(ref Message m)
{
   base.WndProc (ref m);
}

Note that the generated code calls the base class implementation, so the generated code is benign because it is semantically equivalent to not overriding the base class method. IntelliSense will also enforce the correct visibility modifier (public or protected) of the overridden method.

C# New Type Filtering

When you create a new object using the new operator, IntelliSense will pop up a window showing all the type references by the current code. However, unlike Visual Studio .NET 1.0, in version 1.1, IntelliSense will also pre-select the type you are instantiating, as shown in Figure 4.

Figure 4: Type filtering for new objects. When typing new, IntelliSense will suggest to instantiates the type of the variable you are trying to assign to.
The .NET Framework Version dialog lets you select the CLR versions you wish to support. The available options are version 1.1 (the default) only, version 1.0 only, or both 1.0 and 1.1.

Project Settings

The most important change to the project settings options is support for different CLR versions (both for C# and Visual Basic .NET). For C# projects there are also build events and new compiler instructions. These compiler settings provide better affinity to the actual compiler switches available when using the compiler directly via the command line. Following is a rundown of the new features in the same order that they appear in the Project Properties Pages.

Specifying Supported Runtime Version

At present, Visual Studio .NET can only build applications targeting the highest CLR version installed on the machine (this may change in the future). Developers can indicate in the application configuration file which version or versions of the CLR (such as 1.0 or 1.1) the application supports. You can use Visual Studio .NET 1.1 to edit the application configuration file for supported CLR versions.

Figure 5: The Support Runtimes project property.

Here's a cool feature that is only available for application assemblies (such as console or Windows Form application), because a class library assembly does not have a configuration file. In the Project settings dialog box, expand the Common Properties folder and select the General item. On the right pane, expand the Application property group and select the Supported Runtimes property, as shown in Figure 5 (in Visual Basic .NET 1.1 projects, the Supported Runtimes property is under the Build item of the Common Properties folder). Click the ellipsis ... to bring up the .NET Framework Version dialog (see Figure 6).

Figure 6: The .NET Framework Version dialog lets you specify the supported CLR versions, and will edit the application configuration file.

The .NET Framework Version dialog lets you select the CLR versions you wish to support. The available options are version 1.1 (the default) only, version 1.0 only, or both 1.0 and 1.1. Once you make a selection and click Update, the wizard will write your selection to a file called app.config and will place that file in the project's root directory. If your application already has a different configuration file in the bin folder then it will be updated as well.

If you choose to support version 1.1 only of the CLR, the application will always run with version 1.1 of the CLR or not at all, even if the target machine has both version 1.0 and 1.1 of the CLR.

If you choose to support only version 1.0 of the CLR, then your application will run only on machines that have version 1.0 installed, regardless of whether the machine has version 1.1 as well. If you choose to support both version 1.0 and 1.1 of the CLR, if the application is installed on a machine with version 1.1 only, the application will use it. If you install your application on a machine with both 1.0 and 1.1, the application will use version 1.1. If installed on a machine with version 1.0 only, the application will use the 1.0 version.

Build Events

Visual Studio .NET 1.1 introduces an old-time favorite and useful feature: build events. Build events let you specify command line instructions to execute in conjunction with the build process. In the Common Properties, there is a new item called Build Events (see Figure 7). The pre-build command line executes every time before the build starts. The post-build event is the more useful event. You may choose to provide command line instructions that automate parts or all of the deployment of the project's output. You can have Visual Studio .NET 1.1 fire the post-build event always, on successful builds only (the default), or when the build process updates the project's output. For example, if you develop a shared class library, your post build event can install the library in the GAC. To do so, you need to invoke the gacutil command line utility with the ?i switch. Click the ... to bring up the Post-build Event Command line editor.

Figure 7: The project Build Event Properties page. You can specify a commands line to execute before a build starts, command line to execute after a build, and under what condition to run the post build event.

Enter the full path to the utility, such as:

"C:\Program Files\Microsoft Visual Studio .NET
 2003.0\SDK\v1.1\Bin\gacutil.exe" -i

You can use Visual Studio .NET macros to specify the path to the project output instead of hard-coding it. Click the Macros>> button to expand the command line editor, and have it display the list of all predefined macros (see Figure 8). Select TargetPath, and click Insert. Visual Studio .NET will append this macro to your command line:

$(TargetPath)

Figure 8: The Post-build event command line builder dialog lets you type a command line that uses Visual Studio .NET macros that identify variables such as target (output) path and the target filename.

So the complete command line should now look like this:

<path>\gacutil.exe" -i $(TargetPath)

Click OK and you are done. After the build the class library will be installed automatically in the GAC.

Suppressing C# Compiler Warnings

Visual Studio .NET 1.1 lets you instruct the compiler to suppress specific compilation warnings. On the project Properties pages, under Configuration Properties, is the Build item. The Build item contains a new property called Suppress Specific Warnings (see Figure 9) that lets you provide a list of warning numbers to ignore. For example, suppose that you are laying out the skeleton of a class and you want to compile the class, but you don't want the clutter of the additional warnings on code you have not implemented yet. Consider this class definition:

public class MyClass
{
   //warning CS0169: The private field
   //'MyClass.m_Num' is never used
   int m_Num;
   void MyMethod()
   {
      //warning CS0168: The variable 'i' is
      //declared but never used int i;
   }
}

Figure 9: The Build properties page under the project Configuration Properties allows C# developers to specify specific errors the compiler should suppress.

You will get two warnings: one for having an unused private field (warning #169) and one for having an unused local variable (warning #168). To suppress these warnings, simply enter 168,169 on the Build item Suppress Specific Warning property.

Advanced Properties

Under Configuration Properties, in the Advanced item, there are two changes. First, the Incremental Build is set to the default value of False instead of True, as in Visual Studio .NET 1.0.

Incremental compilation compiles only the code that changed since the last build, which can significantly reduce the build time in projects with many files. The Advanced item has a new property, Do not Use Mscorelib, set to False by default (see Figure 10). Using Mscorelib.dll has the effect of automatically including the System namespace. Turning off the automatic include of Mscorelib.dll enables you to use Visual Studio .NET 1.1 with non-Microsoft implementation of most (if not all) of the .NET Framework, and is available in preparation for a point in time in which such implementations will become available.

Figure 10: The Advanced Project configuration Property sets the incremental build property to False by default, and it allows developers not to use the assembly mscorlib.dll.

Tools Options

The Options under the Tools menu contain many new features and changes. Here is a list of the most important of these changes.

Build events let you specify command lines instructions to execute in conjunction with the build process.

Projects and Solutions Environment

The new checkbox, "Track Active Items in Solution Explorer" enables the Server Explorer to automatically track the item you are working with (see Figure 11). The Build and Run Options control what happens when you build and run your projects. The old option of saving all documents when a new build is launched is now split into two options: You can choose to save all changes to all documents and solution files (the default), or choose to save changes to open documents only. In addition, you can explicitly instruct Visual Studio .NET 1.1 to build only the active project or all projects whenever you build or start (by pressing F5) your project.

Figure 11: The Projects and Solutions option allows the Server Explorer to track active items, it provide fine-grained control over what is saved on build.

Visual Basic-Specific Text Editor Options

The Visual Basic-specific Options tab (under Text Editor|Basic) provides two new options (see Figure 12). Both of them are turned on by default. When the "Automatic insertion of Interface and MustOverride members" checkbox is checked, Visual Studio .NET will automatically insert implementation code when adding an interface implementation statement, or when overriding a new method, as shown previously. The second new option is the more interesting one. Many Visual Basic 6 developers miss the procedure separation lines when moving to .NET. In Visual Studio .NET 1.1, procedure separators are back by default (see Figure 13). If you would like to remove them, uncheck the "Show procedure line separators" checkbox on the VB Specific options dialog.

Figure 12: The new VB-Specific options let you enable automation insertion of interface and override implementation, and show VB6-like procedure separators.
Figure 13: Visual Basic.NET 1.1 procedure separator lines.

Controlling C# IntelliSense History

The C# Formatting options under the Text Editor Options item contains the IntelliSense Member Selection options (see Figure 14). By default, the "IntelliSense pre-selects most frequently used members" checkbox is selected, resulting in the IntelliSense behaviors described previously, where new members are selected based on frequency of use, rather than on alphabetical order. If you prefer Visual Studio .NET 1.0 behavior, you need to clear that checkbox. You can also clear the current IntelliSense history by clicking the Clear History button.

Figure 14: Enabling and clearing the IntelliSense history.

Visual Basic Projects Default Options

Most Visual Basic developers prefer to have Option Explicit always turned on. Visual Studio 1.0 developers had to turn it on in every new project. In Visual Studio .NET 1.1, the item called VB Defaults that appears first in the list of Projects allows you to set default options for every new Visual Basic .NET project (see Figure 15). You can control the default setting for Option Explicit, Option Strict, and Option Compare.

Figure 15: Setting default options for Visual Basic.NET projects.
In Visual Studio .NET 1.1, the procedure separators that Visual Basic 6 developers loved are back by default.

Security Configuration

In the first version of .NET (version 1.0), the Internet_Zone code group under the Machine security policy granted the Internet permission set to assemblies coming from the Internet zone. Because of some security concerns and potential security breaches with code coming from the Internet, Microsoft changed this policy in Service Pack 1 for version 1.0. In the service pack, the Internet_Zone code group was associated with the Nothing permission set, thus preventing any such assembly from executing at all. After addressing the issue, .NET 1.1 reassigns the Internet permission set to assemblies coming from the Internet zone, as shown in Figure 16.

Figure 16: The Internet_Zone code group in the Machine policy is set to grant the Intersect permission set to all code originating in the Internet zone.