C#7 Recap

Martijn van Dijk
6 min readFeb 7, 2017

--

What is the purpose of C# 7

While C# has been around the block for some time, it really got a lot of traction since open sourcing the .NET landscape. After the release of C# 6 last year, together with Visual Studio 2015, the team continued to leverage the new features of the completely written from scratch compiler Roslyn.

New features in each version of C# have focused around a specific theme:

  • C# 2.0 introduced generics.
  • C# 3.0 enabled to use Linq by adding extension methods, lambda expressions, anonymous types and other related features.
  • C# 4.0 was about interoperability with dynamic non-strongly typed languages.
  • C# 5.0 simplified asynchronous development with the async and await keywords.
  • C# 6.0 had its compiler, Roslyn, completely rewritten from scratch, and introduced a variety of small features and improvements

The new C# version 7 will continue on this road. The three themes for this version are:

  • Working with Data
  • Improved Performance
  • Code simplification

C# 7 features explained

So now we know what the focus is, let’s split it up and look at some samples!

Working with Data

Pattern matching

With Pattern matching you can easily go through a series of test to check for anything you want and as result do something on a match (or no match). This also works with the switch syntax.

public void PrintStars(object o)
{
if (o is null) return; // constant pattern “null”
if (!(o is int i)) return; // type pattern “int i”
WriteLine(new string(‘*’, i));
}

More expression bodied members

With C# 6 expression bodies were introduced. With this you could simply create a new variable and it would get initialized by the body. With the update you can now create a new get/set variable and use an expression body on the get and set methods!

class Person
{
private static ConcurrentDictionary<int, string> names = new ConcurrentDictionary<int, string>();
private int id = GetId();
public Person(string name) => names.TryAdd(id, name); // constructors
~Person() => names.TryRemove(id, out *); // destructors
public string Name
{
get => names[id]; // getters
set => names[id] = value; // setters
}
}

Improved Performance

Deconstruction

A deconstructing declaration is a syntax for splitting a tuple or other value into parts and assigning those parts individually to new variables. The deconstruction feature doesn’t introduce any new syntax.

class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) { X = x; Y = y; }
public void Deconstruct(out int x, out int y) { x = X; y = Y; }
}
(var myX, var myY) = GetPoint(); // calls Deconstruct(out myX, out myY);

Local functions

You might wonder why Local Functions is under performance improvements. Well, it’s actually simple, when creating a local function, the allocation only needs to happen in the scope of the function. This prevents more memory usage than necessary. In combination with tuple this can be really powerful to execute locally needed functions. Another use case could be when using Xamarin.Android. Since Java has local functions, porting a java library can be easier.

public int Fibonacci(int x)
{
if (x < 0) throw new ArgumentException(“Less negativity please!”, nameof(x));
return Fib(x).current;
(int current, int previous) Fib(int i)
{
if (i == 0) return (1, 0);
var (p, pp) = Fib(i — 1);
return (p + pp, p);
}
}

Generalized async return types

With the generalized Task it is possible to implement your own Task type! While that is very cool, you might not need it very often. But what the .NET team already did is add a default implementation for ValueTask<T>. This is built to prevent the allocation of a Task<T> object in cases where the result of the async operation is already available when you await it.

public ValueTask<Something> BarAsync(string arg)
{
if (arg == null) throw new ArgumentNullException(“arg”);
return CanUseFastPath(arg) ?
new ValueTask<Something>(ComputeSync(arg)) :
new ValueTask<Something>(BarAsyncCore(arg));
}
private async Task<Something> BarAsyncCore(string arg) { … }

Code simplification

Out variables

If you would use out in the past, you needed to declare the the variable before calling the out function. This variable had to be of a type, so using var wasn’t possible. With C# 7 you can out any value and use it afterwards!

public void PrintCoordinates(Point p)
{
p.GetCoordinates(out int x, out var y);
WriteLine($”({x}, {y})”);
}

Tuples

The possibility to use Tuples might be the biggest addition to C# 7! Tuples are a temporary grouping of values, and the most typical usage would be to have multiple return values from a method.

(string, string, string) LookupName(long id) // tuple return type
{
… // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}

Literal improvements

C# 7.0 allows _ to occur as a digit separator inside number literals:

var d = 123_456;
var x = 0xAB_CD_EF;

It is possible to put them anywhere between digits. This is only to improve readability, and they have no effect on the value.

Also, C# 7.0 introduces binary literals, so that you can specify bit patterns directly instead of having to know hexadecimal notation yourself.

var b = 0b1010_1011_1100_1101_1110_1111;

Ref returns and locals

Like you already could pass things by reference with using the ref keyword, you can now also return things by reference, and store them by reference in local variables if you want.

public ref int Find(int number, int[] numbers)
{
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] == number)
{
return ref numbers[i]; // return the storage location, not the value
}
}
throw new IndexOutOfRangeException($”{nameof(number)} not found”);
}
int[] array = { 1, 15, -39, 0, 7, 14, -12 };
ref int place = ref Find(7, array); // aliases 7’s place in the array
place = 9; // replaces 7 with 9 in the array
WriteLine(array[4]); // prints 9

Throw expressions

It is now allowed to throw exceptions in more places, like an expression.

class Person
{
public string Name { get; }
public Person(string name) => Name = name ?? throw new ArgumentNullException(name);
public string GetFirstName()
{
var parts = Name.Split(“ “);
return (parts.Length > 0) ? parts[0] : throw new InvalidOperationException(“No name!”);
}
public string GetLastName() => throw new NotImplementedException();
}

How to enable C# 7

While the work still continues, most of it is available in the new Visual Studio 2017 RC, which you can download here from their website. How Visual Studio 2017 adds support for C# 7 and all the other new features introduced there will be explained in the next blog!

To follow the progress of the language designing, read up on the work on GitHub.

What are the plans for C# 8?

Record types

When you design your model classes you often create an a class with a constructor, properties to save your data, and their backingstore.

Current implementation using C# 7:

class MyPoint
{
int _x;
int _y;
int _z;
MyPoint(int x, int y, int z){
this._x = x;
this._y = y;
this._z = z;
}
public int X {get{ return this._x;}}
public int Y {get{ return this._y;}}
public int Z {get{ return this._z;}}
}

The new implementation:

class Point(int X, int Y, int Z);

As you can see this makes it a lot easier, and more readable to create your models.

Non-nullable reference types

In lots of cases it would make sense to have non-nullable values. In C# 8 this will be added to the language.

int a; //non-nullable value type
int? b; //nullable value type
string! c; //non-nullable reference type
string d; //nullable reference type

Immutable Types

When you don’t want that your class is modified after construction, it will be possible to mark it with the immutable keyword.

public immutable class Point
{
public Point(int x, int y)
{
x = x;
Y = y;
}
public int X { get; }
public int Y { get; }
}

Note: Samples are from the Roslyn Github

--

--

Martijn van Dijk

Microsoft & Xamarin MVP, maintainer of @MvvmCross, contributor to #Xamarin OSS. Co-Founder of @BaseflowIT