Yesterday, at Build, Microsoft released the first public preview of Visual Studio “15” – the next iteration of Visual Studio.

One of the main reasons why you’d want to try it out already is to be able to use some of the heralded C# 7 features – such as binary literals, local functions or pattern matching (to name just a few).

It’s been possible to test out these features in a slightly hacky way before (see Josh’s post) – by building Roslyn from source and deploying it into VS using the CompilerExtension VSIX, but of course it’s much easier and convenient to just use C# 7 features directly in VS “15” now.

In this post I’m gonna show you how to enable the experimental C# 7 features – because they are by default not available.

TL;DR

Add the following conditional compilation symbols to your project: __DEMO__ and __DEMO_EXPERIMENTAL__.

Enabling C# 7 features

So let’s say you want to use local functions in your C# code. You looked at the feature discussion and you wrote this bit of code:

class Program { static void Main(string[] args) { void LocalFunction() { Console.WriteLine("local!"); } LocalFunction(); Console.ReadKey(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 class Program { static void Main ( string [ ] args ) { void LocalFunction ( ) { Console . WriteLine ( "local!" ) ; } LocalFunction ( ) ; Console . ReadKey ( ) ; } }

Unfortunately, Visual Studio is going to complain with the following error message when you try to build this piece of code:

Error CS8058 Feature 'local functions' is experimental and unsupported; use '/features:localFunctions' to enable. 1 2 3 4 Error CS8058 Feature 'local functions' is experimental and unsupported ; use '/features:localFunctions' to enable .

This is a compiler options and you can pass it into csc.exe command line compiler. Of course you’d likely never want to invoke it manually, but would want to use msbuild to build the entire project/solution for you, so you can pass it to the compiler through msbuild too:

MSBuild.exe ConsoleApplication1.csproj /p:Features="localFunctions" 1 2 3 MSBuild . exe ConsoleApplication1 . csproj / p : Features = "localFunctions"

This is hardly ideal though, cause what would be really good, is being able to use the features directly from Visual Studio – and have them picked up by intellisense and the F5 debugger. This is surprisingly easy – just add a conditional compilation symbols to your project: __DEMO__.

You can do that by right clicking your project > Properties > Build > Conditional compilation symbols. This automatically takes care of enabling a bunch of C# 7 features – not just local functions but also binary literals, digit separators and so on.

Enabling pattern matching

Pattern matching is probably the coolest C# 7 feature, but it actually comes in 2 flavours in Visual Studio “15”. The first (using the is operator) is enabled by the same __DEMO__ compilation symbol and allows you do the following:

var foo = "foo"; var s = foo is string x ? x : "not a string"; // prints "foo" Console.WriteLine(s); // if variable foo was not a string, would print // "not a string" 1 2 3 4 5 6 7 8 var foo = "foo" ; var s = foo is string x ? x : "not a string" ; // prints "foo" Console . WriteLine ( s ) ; // if variable foo was not a string, would print // "not a string"

There is also a version of pattern matching that uses a match keyword. That is actually covered by a separate conditional compilation symbol – __DEMO_EXPERIMENTAL__ (symbols are comma separated).

Once you add that to your project you could try out some of the experimental pattern matching code with match, for example the snippet below:

abstract class Animal {} class Dog : Animal { public string BarkLikeCrazy() { return "WOOF WOOF WOOF"; } } class Cat : Animal { } class Swan : Animal { } class Program { static void Main(string[] args) { var animals = new Animal[] { new Dog(), new Cat(), new Swan() }; var organizedAnimals = from animal in animals let sound = animal match ( case Dog d : "woof... " + d.BarkLikeCrazy() case Cat c : "meow" case * : "I'm mute.." ) select new { Type = animal, Sound = sound }; foreach(var animal in organizedAnimals) { Console.WriteLine($"{animal.Type.ToString()} - {animal.Sound}"); } Console.ReadKey(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 abstract class Animal { } class Dog : Animal { public string BarkLikeCrazy ( ) { return "WOOF WOOF WOOF" ; } } class Cat : Animal { } class Swan : Animal { } class Program { static void Main ( string [ ] args ) { var animals = new Animal [ ] { new Dog ( ) , new Cat ( ) , new Swan ( ) } ; var organizedAnimals = from animal in animals let sound = animal match ( case Dog d : "woof... " + d . BarkLikeCrazy ( ) case Cat c : "meow" case * : "I'm mute.." ) select new { Type = animal , Sound = sound } ; foreach ( var animal in organizedAnimals ) { Console . WriteLine ( $ "{animal.Type.ToString()} - {animal.Sound}" ) ; } Console . ReadKey ( ) ; } }

This code above is perform type matching against the aray of animals we defined upfront and is going to print:

ConsoleApplication1.Dog - woof... WOOF WOOF WOOF ConsoleApplication1.Cat - meow ConsoleApplication1.Swan - I'm mute.. 1 2 3 ConsoleApplication1 .Dog - woof . . . WOOF WOOF WOOF ConsoleApplication1 .Cat - meow ConsoleApplication1 .Swan - I ' m mute . .

You can read more about pattern matching in C# 7 here.