What's New in the BCL in .NET 4 Beta 2 [Justin Van Patten]

Visual Studio 2010 and .NET Framework 4 Beta 2 are now available to download.  .NET 4 Beta 2 contains several new BCL features and enhancements in addition to what was included in .NET 4 Beta 1.  Many of these improvements were added in large part due to specific feedback and suggestions reported by customers through Microsoft Connect.

Summary of New BCL Functionality in .NET 4 Beta 2

  • Complex Number
  • Location
  • IObservable<T>
  • Stream.CopyTo
  • Guid.TryParse, Version.TryParse, and Enum.TryParse<T>
  • Enum.HasFlag
  • String.Concat and String.Join overloads that take IEnumerable<T>
  • String.IsNullOrWhiteSpace
  • Environment.SpecialFolder additions
  • Environment.Is64BitProcess and Environment.Is64BitOperatingSystem
  • Path.Combine params support
  • TimeSpan Globalized Formatting and Parsing
  • Stopwatch.Restart
  • StringBuilder.Clear
  • IntPtr and UIntPtr Addition and Subtraction operators
  • ServiceInstaller.DelayedAutoStart
  • ObservableCollection<T> moved to System.dll

Complex Number

System.Numerics.Complex represents a complex number comprised of a real number and imaginary number.  Complex supports both rectangular coordinates (real and imaginary) and polar coordinates (magnitude and phase measured in radians) and supports arithmetic and trigonometric operations.  Complex numbers are used in a number of areas including high-performance computing, graphing and charting, electrical engineering (e.g. Fourier transforms), and other numerical applications.


System.Device.Location (which can be found in System.Device.dll) enables .NET applications running on Windows 7 to determine the current geo-location (e.g. latitude/longitude) of the device.  Windows 7 supports a number of different location sensors, including GPS devices and WWAN radios, and automatically handles transitioning between different sensors — if multiple sensors are available — to provide the most accurate data for the current situation. .NET applications will be able to use this new API to access the following data (if available): latitude, longitude, altitude, horizontal and vertical accuracy, course, speed, and civic address (i.e. country/region, state/province, city, postal code, street, building, floor level).  Note that we are planning to make some changes to the shape of the location API between Beta 2 and RC, so please keep this in mind as you evaluate and use the Beta 2 location API in apps.  A separate blog post will provide more details on the planned changes for RC.


System.IObservable<T> and System.IObserver<T> provide a general mechanism for push-based notifications and can be used to represent push-based, or observable, collections.  Anyone familiar with design patterns will recognize these interfaces as representations of the well-known observer pattern.  IObservable<T> opens up the doors to some exciting new paradigms for event-based and asynchronous programming on .NET.  A great example of this is the Reactive Framework (RX), which is a library of extension methods (not included as part of .NET 4) that implement the LINQ Standard Query Operators and other useful stream transformation functions for IObservable<T>.  F# first-class events also support IObservable<T> and F# includes a library of Observable operators similar to those available in RX.  Imagine being able to do LINQ-style queries against events; this is just one of the kinds of things that IObservable<T> enables.  To help grasp the power of IObservable<T>, I encourage you to watch the Channel 9 videos of Erik Meijer introducing RX and Wes Dyer and Kim Hamilton discussing IObservable<T> in the BCL.

You may be wondering if IObservable<T> is meant to replace events in .NET.  The answer is largely “no,” but you certainly could use it in place of events if you wanted to.  Events are a well-known mechanism for notification in .NET and are already familiar to .NET developers.  As such, they will continue to be the primary mechanism for notification that we recommend for .NET APIs.  The great thing about IObservable<T> is that it is fairly straightforward for callers to convert any existing event into an IObservable<T>.  RX provides built-in methods that do this conversion and F# has support for this built-in to the language.  Stay tuned to this blog for more news about RX in the future.


When working with Streams, how many times have you had to write the following boiler-plate code to read from one stream and write the contents to another stream?

 Stream source = ...;
Stream destination = ...;
byte[] buffer = new byte[4096];
int read;
while ((read = source.Read(buffer, 0, buffer.Length)) != 0) {
    destination.Write(buffer, 0, read);

In .NET 4, you no longer have to write this code.  We’ve added a new CopyTo method to Stream that allows you to simply write:

 Stream source = ...;
Stream destination = ...;

Guid.TryParse, Version.TryParse, and Enum.TryParse<T>

We’ve added TryParse to System.Guid, System.Version, and System.Enum.  Enum.TryParse is generic, a nice improvement over the existing non-generic Parse method, which leads to much cleaner code.

On previous versions of .NET, to parse an enum value, you’d write something like this:

 try {
    string value = Console.ReadLine();
    FileOptions fo = (FileOptions)Enum.Parse(typeof(FileOptions), value);
    // Success
catch {
    // Error

On .NET 4, you can use the new generic TryParse method:

 string value = Console.ReadLine();
FileOptions fo;
if (Enum.TryParse(value, out fo)) {
    // Success


We’ve added a new convenience method to System.Enum that makes it super easy to determine if a flag is set on a particular Flags enum, without having to remember how to use the bitwise operators.  This also allows for more readable code.

In VB:

 Dim cm As ConsoleModifiers = ConsoleModifiers.Alt Or ConsoleModifiers.Shift
Dim hasAlt1 As Boolean = (cm And ConsoleModifiers.Alt) = ConsoleModifiers.Alt ' using bitwise operators
Dim hasAlt2 As Boolean = cm.HasFlag(ConsoleModifiers.Alt) ' using HasFlag

In C#:

 ConsoleModifiers cm = ConsoleModifiers.Alt | ConsoleModifiers.Shift;
bool hasAlt1 = (cm & ConsoleModifiers.Alt) == ConsoleModifiers.Alt; // using bitwise operators
bool hasAlt2 = cm.HasFlag(ConsoleModifiers.Alt); // using HasFlag

String.Concat and String.Join overloads that take IEnumerable<T>

We’ve added new overloads of String.Concat and String.Join that take IEnumerable<T>, adding to the existing overloads that take arrays.  This means you can pass any collection that implements IEnumerable<T> to these APIs without having to first convert the collection into an array.  We’ve also added “params” support to the existing array-based String.Join overload, which allows you to write more succinct code.  In C#:

 String.Join(", ", new string[] { "A", "B", "C", "D" }); // you used to have to write this
String.Join(", ", "A", "B", "C", "D"); // now you can write this


This new convenience method is similar to the existing IsNullOrEmpty method, but in addition to checking if the string is null or empty, it also checks to see if the string only consists of white-space characters, as defined by Char.IsWhiteSpace.  It works great for Code Contract preconditions.

Environment.SpecialFolder additions

We’ve added a number of new values to the Environment.SpecialFolder enum:

  • AdminTools
  • CDBurning
  • CommonAdminTools
  • CommonDesktopDirectory
  • CommonDocuments
  • CommonMusic
  • CommonOemLinks
  • CommonPictures
  • CommonProgramFilesX86
  • CommonPrograms
  • CommonStartMenu
  • CommonStartup
  • CommonTemplates
  • CommonVideos
  • Fonts
  • LocalizedResources
  • MyVideos
  • NetworkShortcuts
  • PrinterShortcuts
  • ProgramFilesX86
  • Resources
  • SystemX86
  • Templates
  • UserProfile
  • Windows

We’ve also added a new overload to Environment.GetFolderPath that takes a new SpecialFolderOption enum, allowing you to specify some additional options, such as “Create” (to create the directory if it doesn’t exist) and “DoNotVerify” (to just return the path without checking if it exists, which can help reduce lag time if the directory is on a network share).

Environment.Is64BitProcess and Environment.Is64BitOperatingSystem

These new convenience APIs make it easy to determine the bitness of the current process and operating system.  Environment.Is64BitProcess is equivalent to calling IntPtr.Size == 8.  Environment.Is64BitOperatingSystem will tell you if the underlying OS is 64-bit.  Note that it is possible for Environment.Is64BitProcess to return false and Environment.Is64BitOperatingSystem to return true if the process is a 32-bit process running on a 64-bit operating system under WOW64.

Path.Combine params support

Have you ever had to nest calls to Path.Combine like this:

 Path.Combine("dir1", Path.Combine("dir2", Path.Combine("dir3", "dir4")));

With .NET 4, you can simply write:

 Path.Combine("dir1", "dir2", "dir3", "dir4");

TimeSpan Globalized Formatting and Parsing

In previous versions of .NET, TimeSpan only supported a single culture-agnostic format for formatting and parsing.  This meant if you called ToString on a French machine the output would not match culture settings, making the application appear not to be globalized.  This is often noticeable in apps that display results from SQL databases that use the frequently used Time column type, because SQL’s Time maps to TimeSpan in .NET.  For example:

 Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Console.WriteLine(new TimeSpan(0, 1, 1, 1, 1));



The output from TimeSpan.ToString is a culture-agnostic format so it uses a '.' as the decimal separator, whereas Double uses ',' based on the current culture.

In .NET 4, System.TimeSpan now supports formatting and parsing based on culture settings via new overloads of ToString, Parse, and TryParse, and new ParseExact and TryParseExact methods.  The default ToString overload still behaves the same for backwards compatibility, outputting a constant, culture-agnostic format, but the new overloads allow you to specify additional culture-sensitive formats.  You can pass the “g” format (general format) to the new ToString overload to specify a culture-sensitive format:

 Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Console.WriteLine(new TimeSpan(0, 1, 1, 1, 1).ToString("g"));



With this new format, the output from TimeSpan is in line with the user’s culture settings.


This is a new convenience method that is equivalent to calling Stopwatch.Reset followed by Stopwatch.Start.


In previous versions of .NET, you could clear StringBuilder by setting the Length property to 0.  This isn’t very discoverable, so we’ve added StringBuilder.Clear as a more discoverable equivalent.

IntPtr and UIntPtr Addition and Subtraction operators

Adding an offset to an IntPtr or UIntPtr can be error prone and often introduces subtle bugs on 64-bit machines if not done correctly.  .NET 4 includes addition and subtraction operators on these types, along with Add and Subtract methods, to help prevent these kinds of errors.


.NET-based services that start automatically can now set a new DelayedAutoStart property to true (recommended), which will delay auto-starting the service until after other auto-start services are started plus a short delay to improve system boot performance when running on Vista or greater.

ObservableCollection<T> moved to System.dll

We’ve type-forward System.Collections.ObjectModel.ObservableCollection<T>, System.Collections.ObjectModel.ReadOnlyObservableCollection<T>, and System.Collections.Specialized.INotifyCollectionChanged from WindowsBase.dll (a WPF assembly) to System.dll.  This allows you to use these collections without taking a dependency on a WPF assembly and enables a cleaner separation between model and view.

We hope you like what we’ve added to the BCL in .NET 4 Beta 2.  Download Visual Studio 2010 and .NET 4 Beta 2 today.  Be sure to let us know what you think and report any bugs you run into.

Update: Added links to the MSDN documentation for each feature throughout. We'd appreciate any feedback on the docs as well. Also updated ServiceInstaller with the correct name (fixed from ServiceProcessInstaller).