Skip navigation
dial with green option NEW and red option OLD pointing at NEW

What's New in .NET 4.5 and Visual Studio 2012

Explore C#'s new async and await keywords, CLR changes, and key features in Visual Studio 2012

A decade after its original release, the .NET Framework is still a preeminent platform for software development. .NET is hot for front- and back-end development. It's hot for a variety of front ends: browsers, desktop, and the new Windows Runtime (WinRT). It works against a variety of databases and back-end styles and with an amazing array of supporting players. It takes a lot of evolution to keep a software development platform in a leading-edge position, and Visual Studio 2012 (formerly known as Visual Studio 11) and .NET Framework 4.5 are the next step in that evolution. My intent here is to take you through some of the evolutionary highlights of Visual Studio 2012 and .NET 4.5 (currently available in Release Candidate and Developer Preview versions, respectively, at the time of this writing), with a look at both the good and the less-than-ideal parts of this new release. For more information on Visual Studio 2012, see "My Favorite Visual Studio 2012 Features" and "Visual Studio 2012 – Not Just About Windows 8."

The two releases accomplish some big goals, such as providing a straightforward asynchronous programming model, Windows 8 support, and letting each team evolve individual parts of .NET. Here I'll focus on changes to the C# and Visual Basic languages, the CLR, and the Visual Studio IDE. But first, what's up with release cycles and version numbers?

Dissecting Version Number Chaos

Visual Studio continues to be the primary mechanism for Microsoft to release new, fully tested technology. But it's a long time between Visual Studio release cycles, and Microsoft wants to get new technology into your hands faster. Microsoft has already released parts of .NET 4.5 via the CodePlex open-source project hosting site and the NuGet package manager -- including Managed Extensibility Framework (MEF) 2, ASP.NET MVC 4, and the Async Community Technology Preview (CTP).

These alternative approaches are great for delivering technology quickly and providing long feedback cycles. The downside of these release mechanisms is that each component has a separate version number, resulting in version numbering chaos. Upcoming version numbers are scattered from 2 to 11.

The .NET Framework receives a half-point increment in the form of .NET 4.5, whereas the languages receive full-point increments, as C# 5 and Visual Basic 11, which is a bit confusing. .NET 4.5 includes library extensions and updates that replace .NET 4.0 libraries. Maintaining the main version number at 4 is a reminder that these aren't side-by-side releases -- installing .NET 4.5 on a machine changes libraries used by applications targeting .NET 4.0. I'll touch on this topic again later when I discuss potential compatibility issues.

C# and Visual Basic have features that fundamentally change how you work with the language, thus justifying a full-point upgrade. More important, languages are tied to compilers, and the compilers are tied to the version of Visual Studio, justifying parallel version number upgrades. The only way to keep this straight is to pay a lot of attention to library and tool version numbers, particularly when reading forums, articles, books, and blog posts.

Now, on to the feature highlights!

Understanding Await and Async

The most important feature of C# 5 and Visual Basic 11 is language support for async programming. There are two scenarios where async programming is useful: CPU-bound operations and I/O or network-bound operations. One of the great things about the new async approach is that it doesn't require additional threads. If you're CPU bound, you need to explicitly start new threads for the CPU-intensive tasks. But you don't need to start a new thread to wait for a server response. I'll simulate network or I/O-bound operations with an explicit delay. For CPU-bound tasks, the same approach applies, although in that case you'll also need to consider cross-threading issues such as deadlocks.

Most of the time (maybe 90 percent of the time), you don't need to understand how async works. The beauty of the language implementation is that the naïve view of the code is generally close enough. When you delve more deeply, focus on the logical view rather than platform-specific implementation.

To operate on a single thread, the async model relies on events, requesting an action and handling an event when it finishes. Calling an async method from a console app might look perfectly normal, as shown in Figure 1.

    class Program
    static void Main(string[] args)
        var x0 = new Async0();
        Console.WriteLine("2. Returning Async0");

The Async method kicks off an action and returns, allowing the WriteLine and ReadLine methods to execute. Sometime later, the action is completed. Async suffixes on method names are very important because they make it possible to predict the code's behavior.

The Async0 method that's shown in Figure 2 uses the new async and await keywords.

    public class Async0
    internal async Task Async()
        int result = await LongOp(); 
        Console.WriteLine("4. Operation completed.  Result is {0}.", result);

    public async Task LongOp()
        Console.WriteLine("1. Attempting long-running operation...");
        //Simulate a process that takes between 2 and 4 seconds to complete.
        var r = new Random();
        await Task.Delay(r.Next(2000, 4000));
        Console.WriteLine("3. Done!");
        return 42;

The Async0 method is subtly different from normal .NET code because it lacks a return statement and the return type of the LongOp doesn't match the method signature. This is because the await statement is a new kind of return. You can count on await to do these things:

  • Create a Task object.
  • Create a continuation lambda that can later
  • assign the called task result to the variable if the await is assigned.
  • run the remainder of the async method.
  • Start the action (LongOp, in this case).
  • Return the Task object to the calling program, unless it's a void method.
  • End method execution.

The async method await statement splits the method. The code before the async method runs when the method is called. The code after await is bundled into a lambda delegate to run when the awaited operation is completed. If the return value of the method is a generic task, the return of the continuation must be assignable to that generic type; failing to return a value generates the compiler error not all code paths return a value. The return value of the continuation is placed into the Result property of the Task object.

The following code

int result = await LongOp();

is identical to this code:

Task task = LongOp();
await task;
int rslt = task.Result;

The async modifier is required in methods that use await and signals to the compiler and other programmers that the method is special. I included numbers in the sample output of Figure 1 and Figure 2 that indicate the code-execution order.

Digging Deeper into Async

There are two important implications of async programming. I already mentioned that it doesn't rely on multiple threads, which alleviates contention and UI thread issues. Also, this approach relies on the Windows message pump, or an analogous service, and therefore requires that normal operation and specifically the message pump be maintained. (An experienced .NET coder caught up in async features failed to notice that he had forgotten the ReadLine statement in his test console application.) In order to keep the main thread active and execute continuations smoothly, you must also use Task.Delay instead of Thread.Sleep to simulate delays and avoid long loops and intensive operations on the main thread. If your application exits or the main thread is blocked, async operations won't run as expected.

You're unlikely to use async code that's as simple as my sample in Figure 1 and Figure 2. Real-world applications need to consider timeouts, exceptions, and cancellation. You can find more detailed information about cancellation in the .NET team's .NET Framework Blog, but I'll give you a general idea of what to expect before I go on to cover other .NET 4.5 and Visual Studio 2012 features.

Compiler magic allows normal-looking try/catch exception handling in async methods. Exceptions appear to pass up a call stack between continuations. However, these exceptions don't propagate into synchronous code because that code has moved on to other operations. Instead, the task is marked as faulted, and an aggregate exception is included in the Exception property of the task.

An interesting wrinkle is that the aggregate exception approach is used for all code in the async method, not just the code in the continuation. If an exception is thrown in the async method before the await keyword, the exception won't propagate through a wrapping try/catch. Instead, the task will appear faulted and the exception thrown will be contained in the aggregate exception.

The CancellationTokenSource class provides communication between code capable of canceling and operations that can be canceled. The action that can perform the cancel, such as a Cancel button, needs a reference to the CancellationTokenSource and calls its Cancel method to request cancellation. The CancellationTokenSource's CancellationToken is passed to the operation that can be canceled. Many of the async methods in the .NET Framework have an overload that takes a cancellation token. If you're creating your own async operations, they can poll the value of the cancelToken.IsCancellationRequested property, register a callback with the token, or when necessary use the WaitHandle of the CancellationToken to respond to cancellation. When an operation is canceled, an OperationCanceledException or the derived TaskCanceledException is thrown. Throwing the exception blocks the processing of any continuations.

This async approach keeps your code simple when you combine multiple async operations. You can simultaneously start multiple operations and wait for any or all of them to finish with the WhenAny and WhenAll shared methods of the Task class. You can also run async operations in order with multiple await statements. The second await appears in the continuation of the first await and therefore begins execution when the first awaited task is completed. You can use any combination of these to get the execution order you need.

You can handle timeouts either with the CancelAfter method of the CancellationTokenSource class or by running your task as part of a WhenAny with a Task.Delay method. You can raise a TimeoutException so that code inspecting your Task object can post the correct message to the user.

Accessing Caller Information

C# and Visual Basic now include a mechanism for retrieving the name and line number of the caller. The code might be a little surprising:

public void Foo(
    [CallerMemberName] string memberName = "",
    [CallerLineNumber] int lineNumber = 0)
    Console.WriteLine("Caller: {0} Line: {1}", memberName, lineNumber);

If a value isn't passed for a parameter with an attribute of CallerMemberName, the compiler supplies the information. The calling code ignores the parameter, although unfortunately these parameters still appear in IntelliSense. The two most likely scenarios are custom logging and INotifyPropertyChanged implementations.

Sharing Projects between Visual Studio Versions

Projects and solution files are now compatible between versions of Visual Studio. In previous versions, opening a project or solution in the latest version of Visual Studio blocked it from opening in any previous version. As a result, you often had to use multiple versions of Visual Studio and remember which version of Visual Studio each of your projects belonged in. Changing this approach required a commitment for a versioning strategy for all the files that Visual Studio uses. Kudos to Microsoft for finally making this commitment.

Looking at CLR Changes

At the CLR level, major changes are portable libraries, changes to garbage collection (GC), and updates to the MEF. Other changes include regular expression engine timeouts, cultures for application domains, console support for Unicode (UTF-16), better performance when retrieving resources, and zip compression improvements.

The new Portable Class Library project type lets you write code once and share it across multiple platforms. The Project Properties dialog box for this type lets you specify the target platforms. The compilers and Visual Studio IntelliSense restrict the subset of features to those available on all targeted platforms.

Most of us are happy when we hear GC is better, but we rarely think about it. In .NET 4.5, generation 2 collection no longer blocks generation 0 and generation 1 collection, fixing a potential hang-up. Also, if you use server garbage collection, generation 2 collection now runs in a separate thread. For most developers, it's enough to know that garbage collection runs a bit better with much less blocking.

.NET 4.5 includes a major update to one of my favorite tools: MEF. MEF V1 was missing some important features. The most important addition is that MEF V2 adds support for resolution of open generics. V1 generally relied on attributes, which created a dependency on MEF in your code. This was undesirable from a separation-of-concerns perspective. Rules-based inference in V2 lets you define your own conventions and remove MEF artifacts from code while remaining configuration-free. MEF V2 also includes improved diagnostics and more granular scope definition.

Watching for Compatibility Problems

I need to back up and cover some of the painful things about the new releases. The addition of new stuff to .NET and Visual Studio -- even fantastic, exciting new stuff -- means that there are more "fine-print details" for you to know. We certainly live in interesting times.

.NET 4.5 isn't a side-by-side install; rather, it's an in-place upgrade. (See Scott Hanselman's blog post ".NET Versioning and Multi-Targeting" for more information.) This means it extends the .NET Framework with new libraries and makes alterations in the .NET 4.0 libraries. The new .NET 4.0 libraries might be installed by other applications on computers running your applications. Theoretically, this is all backward-compatible, and no one notices. But there's a chance that the upgrade will cause one of three types of compatibility problems: compilation issues, binary compatibility, or serialization problems.

It will be pretty obvious if your code doesn't compile with the new libraries. For example, you might have used an interim release or CTP that has now been replaced. These problems should be pretty easy to track down and fix.

Binary compatibility problems are more serious, although Microsoft has worked very hard to avoid them. Do as much testing as you can against the new version of the .NET 4.0 libraries that are installed with .NET 4.5, regardless of when you plan to redeploy your application and whether you're targeting .NET 4 or 4.5. Another area to test for possible compatibility issues is serialization, when serialized objects are passed between different versions of .NET 4.0.

Ensuring You're Safe from a Breaking Change

There's a subtle breaking change (i.e., a change that could change the behavior of your previously written code) in the compilers in Visual Studio 2012. Special handling has been added for foreach loop variables in lambdas. This happens when you recompile using Visual Studio 2012 -- regardless of the version of the .NET Framework you target. The change affects only code that uses a foreach loop variable in a lambda expression. Figure 3 shows a contrived example of the effect of a breaking change on a foreach loop in a lambda expression.

    public void ClosuresTwo()
        var actions = new List();
        var list = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        foreach (var i in list)
        { actions.Add(() => Console.WriteLine(i)); }

    foreach (var i in actions)
        { i(); }

In the example in Figure 3, pre-.NET 4.5 compilers create Intermediate Language (IL) code that outputs 9,9,9… because local variables are included in the lambda as a closure. The closure means the actual variable, not the value or a copy of the variable, is included in the lambda. C# 5 and Visual Basic 11 compilers create IL code that outputs 0, 1, 2, 3…9. The compilers add an extra variable scoped to the loop and assign it the value of the loop variable as the loop executes. This hidden variable is included in the closure instead of the loop variable. This happens for foreach, but not for loops.

I hate breaking changes, but this one makes sense because these problems can be very hard to see, particularly when continuations implicitly create lambdas. There's a good chance you don't have code that uses the loop variable in a closure, but you can't guarantee it without evaluating your code using a tool. If you're in Visual Basic, or you use JetBrains' ReSharper, you receive a warning and can act on it. If you code in C#, look for third-party software development tools (with 30-day free trials) that catch this problem.

Exploring the Visual Studio 2012 IDE

Visual Studio 2012 itself includes both superficial changes such as fonts and colors and real changes to behavior. It includes extensive improvements to supporting tools, especially unit testing and parallel debugging. The IDE is more responsive in avoiding freezes when you're typing. There's a decent code editor for JavaScript. There's an update to Team Foundation Server (TFS); for more information, see "What's New in Visual Studio TFS 2012." The error limit has been removed for command-line compilation. That's just a sampling, and of course, there have been general bug fixes.

The initial release of the Visual Studio 2012 CTP had a very depressing grey appearance and no colors in the icons. Microsoft responded to user input by lightening the grey background and tossing a little color into the icons. There are still things to dislike, but the appearance is workable.

I'm really excited about new functionality. I love that you can float an entire set of tabs. In Visual Studio 2010 you could float individual files, littering windows about on your monitors and generally making a mess. Now, you can float groups of files in individual tab wells, as shown in Figure 4. You can drag files between them. You can also select multiple files with Ctrl+Click, create a new horizontal or vertical tab group, and then use Float All to float the group.

Figure 4: Using a floating tab well in Visual Studio 2012
Figure 4: Using a floating tab well in Visual Studio 2012

Another great feature is pinning tabs. This lets you organize files you use often and explicitly order them. There are three levels of tabs within Visual Studio: pinned, normal tabs, and temporary preview. Opening a file with an indirect action such as Go To Definition or single-clicking in Solution Explorer or the Find Results window reuses the same preview tab on the right. You can move the temporary tab to the normal main tab well by clicking an icon, clicking Open Tab on the right-click context menu, pressing Ctrl+Alt+Home, or most commonly, by editing the file.

One trick: By default, floating a tab removes the pinned status. This is probably not the behavior you want. Fix it in the new Tabs and Windows option in Tools, Options, Environment.

Another great feature of Visual Studio 2012 is Quick Launch, accessed with Ctrl+Q. Type part of a name, and a drop-down list will show any matching items from menus, options, and currently open documents. Initially the drop-down shows a few items from each category, forcing the results to fit into the drop-down. Press Ctrl+Q again to cycle through the full lists of matches. Clicking a menu item executes it, and clicking a window or option opens the corresponding window. Options is particularly cool since you skip the step of opening Tools, Options and hunting for the correct dialog box.

There are two modes of the new code-clone detection feature, shown in Figure 5:

Figure 5: Code-clone detection in Visual Studio 2012
Figure 5: Code-clone detection in Visual Studio 2012

If you highlight one or more statements and select Find Matching Clones in Solution in the right-click context menu, you'll find all matching sets of statements. The matches don't have to be exact. White space will be ignored, and some differences in naming will result in a "strong" match. If you run Analyze Solution for Code Clones, you'll find any code in your solution that has more than 10 matching statements. "Medium" matches can occur even if the statements don't appear in the same order.

On the downside, Microsoft has removed macro capability from Visual Studio 2012. You can't create or edit macros, and you can't run existing ones. Most programmers don't use macros, but this is a huge loss for the minority that do. Replacement strategies include using Windows PowerShell or Visual Studio extensions.

If you've been using the Productivity Power Tools for Visual Studio 2010, you'll be happy to see some features from it in the 2012 version of the extension, but you'll miss some of the features that didn't make it. I'll miss Ctrl+Click and automatic brace completion in C#.

Coordinating with Windows 8

The release of Visual Studio 2012 is tied to the Windows 8 release -- which is sensible because Visual Studio provides the libraries required for WinRT. The new WinRT API provides support for cloud-based data, sandboxes itself for protection in a dangerous world, and allows enough constraint for a store ecosystem. Microsoft also did a lot of work to prepare for the new Metro user experience.

You can write for WinRT and Metro using C# with XAML, JavaScript with HTML5 and Cascading Style Sheets (CSS), or C++ with DirectX or XAML. Although these languages are familiar, using the WinRT API limits code reuse with non-WinRT applications, unless open-source libraries sufficiently abstract the differences. Your WinRT application will be sandboxed and interact with the local machine and other applications only through charm interfaces and only with explicit user permission.

Explore the New Features

The release of the new versions of Visual Studio and the .NET Framework is one more step in the arc of tool updates that keep the development tools we depend on relevant and vibrant. Even at this whirlwind pace, I've skipped far more than I've covered. (Check out the articles listed in the Learning Path for more information about the new releases.) There are significant changes to almost every major library, and I barely scratched the surface of the changes in Visual Studio itself. Grab Visual Studio 2012 and give it a whirl.

As you move into Visual Studio 2012 and .NET 4.5, make time to learn about the new async features and your favorite library. Be patient with the new Visual Studio appearance and learn more about how it can improve your productivity. Look for information on what's changed in the libraries you use most. The upgrade isn't massive or disruptive, but it offers many opportunities for you to improve your programming.

Learn more about Visual Studio 2012 and .NET 4.5:

Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.