What's New in C# - Pattern Matching and Local Functions

What’s New in C# 7.0? – Digit Separators, Reference Returns, and Binary Literals

Thanks to frequent updates and continuous support, C# remains one of the most popular modern development languages. The latest major version, released in March of 2017 and coinciding with the release of Visual Studio 2017, brings with it a number of new features, which we’ve been covering in our ongoing series, What’s New in C# 7.0?. Thus far we’ve investigated a number of topics:

  • In Part 1 we thoroughly explored tuple types, tuple literals, and out variables.
  • In Part 2 we looked at pattern matching and local functions.

For part 3 today we’ll examine the digit separator, binary literals, reference returns and local reference variables, so let’s get to it!

Digit Separator

A small but handy little feature introduced in C# 7.0 is the digit separator character, which takes the form of a single underscore (_). This separator can be used within any numeric literal as a means of improving legibility. The existence of a digit separator in a numeric literal does not change the value in anyway. Any given number is always the same to the common language runtime, regardless of whether it uses separators or not.

This feature can be particularly useful when creating extremely lengthy numeric literal values. For example, it canact as a thousands-place separator:

Obviously, the first value is quite difficult to read at a glance, whereas it’s relatively easy to count the thousands places in the second number and deduce it’s somewhere around 123 quadrillion. While scientific notation can often be used for large numbers, in situations where exact precision is necessary (like above), the digit separator comes in handy.

Binary Literals

C# 7.0 also provides the ability to create binary literal values (base 2 numbers, effectively). This adds onto the other numeric literal capabilities, such as hexadecimal literals, so you can write out exactly the value you mean to, in whatever format best suits your needs. Moreover, we can also use the new digit separator within hexadecimal and binary literals.

Here we see the standard and digit-separated versions, using all three numeric literal forms:

The output shows all our numbers are equivalent, as expected:

Note: We’re using the Utility.Logging class in these examples, which can be found below:

Returning References and Local Reference Variables

In the past, using references in C# merely consisted of passing an argument by reference. The ref keyword would precede the parameter type in the method definition. To coincide with the parameter ref keyword, ref would also come before the argument value being passed to said method. For example, here the SetByReference(ref int, int) method changes the value at the reference location to value, so we can change the index 2 array element from -42 to 24601:

Now, in C# 7.0 the ref keyword can be used in a couple more useful situations: Returning a reference value from a method, and creating a local variable to store a reference value. To illustrate these new features we have a simple Library class, the full code of which can be found below, then we’ll explain what’s going on in more detail to follow:

Our goal is to retrieve a reference from a Book Array collection based on a searched book Title property value. To accomplish this we have the GetReferenceByTitle(string, Book[]) method:

This method just loops through the books array, by index, until it finds a matching Title, at which point it returns the reference to that matching Book element using the ref keyword.

To illustrate how this might differ from the “usual” method of returning by-value, we have the GetValueByTitle(string, Book[]) method:

Since Book[] is an IEnumerable collection we can use LINQ, so with just a single little line of code we can search and return our matching Book element value.

To illustrate how the ref return value works we start by creating our Book array collection, then specify the Book Title value we want to search for. In this case, we’re going to be looking in our collection for "Moby Dick". We also call Array.FindIndex(T[], Predicate<T>) and output the actual index value that our searched Book was found at, which we’ll use at the end of the example:

The output of this initial setup code appears below:

We’ve confirmed that the collection contains four Books, and that "Moby Dick" is at index 1, so now let’s make use of new reference return value functionality. To do so, we preface the call to GetReferenceByTitle(string, Book[]) with the ref keyword, which indicates we expect a reference to be returned. We also want to assign that returned reference value to a local variable, which is accomplished by preceding our var keyword with the ref keyword during assignment. Thus, here the local variable named reference contains the reference value that is returned by GetReferenceByTitle(string, Book[]):

We’ve also made a call to GetValueByTitle(string, Book[]) with the same arguments passed, so we can output and compare the results of both types of returns (reference vs value):

Excellent! So far everything is working as expected, so now we can use our local reference variable (reference) to change the value that said reference refers to. In this case, we’ll create a new Book instance for "Game of Thrones" (the new season is awesome so far, by the way). Just to confirm we’re accessing the original array collection at the same location that "Moby Dick" was originally found at, we’re outputting the value at the index location, which we saved earlier:

As intended, the output confirms that reassigning the reference variable successfully updated the underlying element value within our original books collection:

Stay tuned for future parts in this series where we’ll continue exploring the new features introduced in C# 7.0! And don’t forget, the Sharpbrake library provides robust exception tracking capabilities for all of your C# and .NET applications. Sharpbrake provides real-time error monitoring and automatic exception reporting across your entire project, so you and your team are immediately alerted to even the smallest hiccup, and can appropriately respond before major problems arise. With a robust API and tight integration with the powerful Airbrake web dashboard, Sharpbrake will revolutionize how your team manages exceptions.

Check out all the great features Sharpbrake brings to the table and see why so many of the world’s top development teams use Airbrake to dramatically improve their exception handling practices!