C# 7 Features Previewed

Over the last year we’ve shown you various features that were being considered for C# 7. With the preview of Visual Studio 15, Microsoft has decided to demonstrate the features to make it into the final release of C# 7.

Tuple Value Types

.NET has a tuple type, but in the context of C# there are a lot of problems. Being a reference type, you probably want to avoid using it in performance sensitive code as you have to pay for GC costs. And as they are immutable, while making it safer for sharing across threads, making any changes requires allocating a new object.

C# 7 will address this by offering a tuple as a value type. This will be a mutable type, making it more efficient when performance is essential. And as a value type, it makes a copy on assignment so there is little risk of threading issues.

To create a tuple, you can use this syntax:

var result = (5, 20);

Optionally, you can name the values. This isn’t necessary, it just makes the code more readable.

var result = (count: 5, sum: 20);

Multi-value Returns

Returning two values from one function has always been a pain in C-style languages. You have to either wrap the results in some sort of structure or use output parameters. Like many functional languages, C# 7 will do the first option for you:

(int, int) Tally (IEnumerable<int> list)

Here we see the basic problem with using generic tuples: there is no way to know what each field is for. So C# is offering a compiler trick to name the results:

(int Count, int Sum) Tally (IEnumerable<int> list)

We’d like to stress that C# isn’t generating a new anonymous type. You are still getting back a tuple, but the compiler is pretending its properties are Count and Sum instead of Item1 and Item2. Thus these lines of code are equivalent:

var result = Tally(list);

Note that we do not yet have a syntax for multi-assignment. Presumably when it happens, it will look something like this:

(count, sum) = Tally(list);

Beyond simple utility functions such as this, multi-value returns will be useful for writing asynchronous code, as async functions aren’t allowed to use out parameters.

Pattern Matching: Enhanced Switch Blocks

One of the long standing complaints of VB and functional programmers alike is that C#’s switch statement is extremely limited. VB developers want ranges, while those who used to F# or Haskell want decomposition-style pattern matching. C# 7 intends to offer both.

When pattern matching on types, you can create variables to hold the result of the cast. For example, when using a switch on a System.Object you could write:

case int x:

If the object is an integer, the variable x will be populated. Otherwise it will check the next case block in a top to bottom fashion. If you want to be more specific, you can use range checks:

case int x when x > 0:
case int y:

In this example, if the object is a positive integer the x block will be executed. If the object is zero or a negative integer, the y block will be executed.

If you want to check for null, simply use this syntax:

case null;

Pattern Matching: Decomposition

So far we’ve just seen an incremental improvement over what is available in VB. The real power of pattern matching comes from decomposition, where you can tear apart an object. Consider this syntax:

if (person is Professor {Subject is var s, FirstName is "Scott"})

This does two things:

  1. It creates a local variable named s with the value of
  2. It performs the equality check
    ((Professor)person).FirstName == "Scott"

Translated into C# 6 code:

var temp = person as Professor;
if (temp != null && temp.FirstName == "Scott")
   var s = temp.Subject

Presumably we’ll be able to combine enhanced switch blocks in the final release.

Ref Returns

Passing large structures by reference can be significantly faster than passing them by value, as the latter requires copying the whole structure. Likewise, returning a large structure by reference can be faster.

In languages such as C, you return a structure by reference using a pointer. This brings in the usual problems with pointers such as pointing to a piece of memory after it has been recycled for another purpose.

C# avoids this problem by using a reference, which is essentially a pointer with rules. The most important rule is that you can’t return a reference to a local variable. If you tried, that variable would be on a portion of the stack that is no longer valid as soon as the function returns.

In the demonstration, they instead returned a reference to a structure inside an array. Since it is effectively a pointer to an element in the array, the array itself can be modified. For example:

var x = ref FirstElement(myArray)
x = 5; //MyArray[0] now equals 5

The use case for this is highly performance sensitive code. You wouldn’t use it in most applications.

Binary Literals

A minor feature is the addition of binary literals. The syntax is simple prefix, for example 5 would be “0b0101“. The main use cases for this would be setting up flag based enumerations and creating bitmasks for working with C-style interop.

Local Functions

Local functions are functions that you define inside another function. At first glance, local functions look like a slightly nicer syntax for anonymous functions. But they have some advantages.

  • First, they don’t require you to allocate a delegate to hold them. Not only does this reduce memory pressure, it also allows the function to be in-lined by the compiler.
  • Secondly, they don’t require you to allocate an object when creating a closure. Instead it just has access to the local variables. Again, this improves performance by reducing GC pressure.

Presumably the second rule means that you can’t create a delegate that points to a local function. Still, this offers organizational benefits over creating separate private functions to which you pass the current function’s state as explicit parameters.

Partial Class Enhancements

The final feature demonstrated was a new way to handle partial classes. In the past, partial classes were based around the concept of code-generation first. The generated code would include a set of partial methods that the developer could implement as needed to refine behavior.

With the new “replace” syntax, you can go the other way. The developer writes code in a straight forward fashion first and then the code generator comes in and rewrites it. Here is a simple example of what the developer may write,

public string FirstName {get; set;}

Simple, clean, and completely wrong for a XAML style application. So here’s what the code generator will produce:

private string m_FirstName;
static readonly PropertyChangedEventArgs s_FirstName_EventArgs 
                   = new PropertyChangedEventArgs("FirstName")

replace public string FirstName {
   get {
      return m_FirstName;
   set {
      if (m_FirstName == value)
      m_FirstName = value;
      PropertyChanged?.Invoke(this, m_FirstName_EventArg);

By using the “replace” keyword, the generated code can literally replace the hand-written code with the missing functionality. In this example, we can even handle the tedious parts that developers often skip such as caching EventArgs objects.

While the canonical example is property change notifications, this technique could be used for many “Aspect Oriented Programming” scenarios such as injecting logging, security checks, parameter validation, and other tedious boilerplate code.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.