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

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

  • Comments 32

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).

  • Thanks for the great overview.

  • Excellent overview.  Minor tweaks like these go a long way to improving readability and reducing pain.  The new Path.Combine overload is definitely handy - long path combinations quickly become ugly.

    I also like the bitwise HasFlag helper.  Bitwise checks are pretty rare, but whenever they do come up I always have to double check my operators to make sure I'm checking the flag correctly (and then still feel unsure about the result).

  • These additions are awesome. I've been slightly annoyed by at least half of these. I'm glad you guys not only add new big features, but also add small refinements to take away small annoyances.

  • complex number,cool! What about SIMD vector support:)

  • regarding the ServiceProcessInstaller.DelayedAutoStart


    You say 'which will delay auto-starting the service until after other auto-start services are started'

    What happens if there are two services with ServiceProcessInstaller.DelayedAutoStart


  • I wish string.Intern(null) simply returned null instead of throwing an ArgumentNullException. It's annoying to have to write:

     if (s != null) s = string.Intern(s);


     some_method(s != null ? string.Intern(s) : null);

    string.Intern() should do its best to replace identical strings with one canonical instance but nothing more. If it can't find a match, it returns the original string. 'null' won't match anything so it should be returned unmodified too.

    It would be nice to be able to flush the intern pool programmatically too (get rid of the unreferenced strings). Even string.Unintern(s) might help in specific cases.

  • Nice,

    A implementation of Quaternions would be of interest since they are very usefull. Especially in vector math. Arbitrary sized matrices(Maybe with some type of template expansion for perf), or more advanced mathlib with interchangable implementation,(LINQ/MEF architecture). Handling of CMYK/ or colorspaces in graphics?

  • I've had my own Enum.TryParse<T> for a long time now - Thanks for adding it.

    How about adding compiler support that will generate

     Enum.TryParse(value, out fo)

    when I write

     FileOptions.TryParse(value,out fo)

    Just much more readable

  • Hi Justin,

    Thanks for the great overview! These are many very good additions, my favorite one being Enum.HasFlag as I have to do a lot of interop stuff ;)

    Do you think there is a chance to also get something like

    T Enum.SetFlag<T>(T flag, bool set)


       if (set)


           return this | flag;




           return this & ~flag;



    ? That would be very cool as checking for a flag is usually the easier operation compared to selectively setting and clearing flags which always requires an if and two bit modification statements.



  • All great stuff, long overdue and will be very useful going forward. I wish the .NET Framework team as a whole would concentrate more on the "little" things like this that actually make a big difference in every day programming.

    I do have a question though: why do the TryParse methods use an out variable, instead of returning a nullable result? The syntax for out variables is awkward, and the Framework Design Guidelines specifically state to avoid them for that reason. For reference types you could just return null (as far as I know, null is never a valid result of a Parse operation), and for value types you could return a nullable version. This would make using these TryParse methods much simpler. Although I imagine it is too late to change them now.

  • Very cool. Stream.CopyTo(), Enum.TryParse(), Enum.HasFlag() and Path.Combine() are my favorite in this list, probably because they're not the end of the world to implement on my own, it just makes my code more readable to have these available natively.

    One question, and I'm not suggesting a name change, but is String.IsNullOrWhiteSpace actually IsNullOrEmptyOrWhiteSpace?

  • David Nelson, you want the out param so that you can inline the call in an If statement. Otherwise you'd have to create a variable, assign the result to it and then check it for null or worse, make two calls to TryParse, the first checking for not null and the second to get the value. Since TryParse is a convenience method intended to help make code more readable the out param version makes the most sense.

  • @Eyal

    > How about adding compiler support that will generate

    > Enum.TryParse(value, out fo)

    > when I write

    > FileOptions.TryParse(value,out fo)

    Since TryParse is a static method, and any enum type derives from System.Enum, it's already precisely how it works with no special compiler support.

  • Generic Enum.TryParse is great, but what about providing generic overloads for existing Enum.Parse and Enum.IsDefined? The inconsistency between TryParse and Parse looks is especially glaring.

  • What is the buffer size used in the Stream.CopyTo functionality? I'm guessing that isn't configurable.

Page 1 of 3 (32 items) 123