Tools4ever Tech Blog

De nieuwste features in c# 7.0 uitgelicht

Roy Versteeg - Sr. Software Engineer | 27 september 2016

C# 6.0 is al weer een tijdje uit en binnenkort staat C# 7.0 al klaar voor software developers. In dit blog bekijk ik een aantal nieuwe features die het leven van een C# developer makkelijker kunnen maken.

Literals

In het verleden kon qua integer literals alleen gebruik gemaakt worden van decimale, octale en hexadecimale representatie. Het komt echter vaak voor dat je een bitfield wilt toekennen en dan is het vervelend dat deze eerst omgerekend moet worden naar een representeerbaar getal.

In C# 7.0 worden binary literals geïntroduceerd met een 0b prefix (vergelijkbaar met de 0 prefix voor octaal, en 0x voor hexadecimaal).

var b = 0b010101;

Tevens is het vanaf C# 7 mogelijk om decimal separators toe te voegen om lange literals leesbaarder te maken. Deze separators kunnen in zowel binaire, octale, decimale als hexadecimale literals gebruikt worden.

var large = 1_000_000_000;

Local Functions

Soms zijn er binnen een methode kleine stukjes functionaliteit die vaak hergebruikt worden. Daar wordt dan meestal een functie binnen de class voor  gemaakt. Het is echter jammer dat daarmee de class scope vervuild wordt, aangezien de functionaliteit eigenlijk alleen binnen de functie nodig is. Sinds er lambda functies zijn is het al mogelijk om dergelijke functionaliteit daarmee op te lossen. Die syntax is echter niet altijd fijn. Tevens is het bijvoorbeeld niet mogelijk om in een lambda functie een iterator te implementeren.

Met de nieuwe local functie feature is dit wel mogelijk. Die functie kan alle variabelen in de scope van de outer function capturen, en kan tevens een iterator method zijn.

 

Tuples

Het komt vaak voor dat je een aantal bij elkaar horende variabele door wil geven binnen je programma. Meestal schrijf je daar dan een simpele data container class voor. Dat is erg veel typewerk. In voorgaande versies van C# is het Tuple data type al geïntroduceerd. Tuple is echter niet meer dan een aantal class definities met hoogstens 8 type-parameters met members voor ieder item van het corresponderende type. Voor het snel teruggeven van data uit een methode lijkt het soms handig om hiervan gebruik te maken, maar achteraf is het vaak niet meer duidelijk wat er nou precies in welke property van de Tuple zat. Daarnaast is de constructie beperkt tot maximaal 8 variabelen (toegegeven dat je over je design na mag gaan denken als je er al zoveel nodig hebt ;)).

In C# 7 worden Tuples echt onderdeel van de taal en kun je ook namen geven aan de properties van een Tuple.

 

Aan de aanroepende kant kan je gewoon weer min en max aanroepen op het resulterende object dat je krijgt.

 

Het is ook mogelijk om de velden van de resulterende Tuple direct toe te wijzen aan variabelen. Op deze manier kunnen Tuples ook gebruikt worden als simpele oplossing voor multiple return values.

 

Out Parameters

Soms zijn er functies die out parameters hebben. Zeker als er meerdere out parameters zijn is het vervelend dat die eerst allemaal gedeclareerd moeten worden voordat de functie aangeroepen kan worden. De code die dat oplevert leidt alleen maar af van hetgeen je daadwerkelijk wilt bereiken. In C# 7 is het mogelijk om deze out parameters binnen de functie aanroep zelf te declareren. Op deze manier bespaar je een declaratie regel. Er vindt momenteel nog discussie plaats of het mogelijk zou moeten zijn om op deze manier de variabele naam achterwege te laten voor parameters waar je niet in geïnteresseerd bent. Op die manier zou de scope niet vervuild raken met ongebruikte variabelen.

 

Ref return values & ref variables

Voor C# 7 konden alleen parameters als ref worden gedefinieerd. Nu is het ook mogelijk om variabelen en return types als reference te declareren. Daarmee is het bijvoorbeeld mogelijk om een reference naar een element in een array te retourneren die later binnen de code aan te passen is.

 

Pattern Matching

Eén van de, wat mij betreft, meest veelbelovende toevoegingen aan C# is pattern matching. In versie 7 wordt helaas slechts een gedeelte geïmplementeerd. Met de toekomstige toevoeging van Record types en uitgebreidere matching wordt het nog mooier.

Met pattern matching kan een expressie worden getest tegen een type patroon. Bij die test kan menook direct één of meerdere variabelen introduceren. Pattern matching  kan ook voor C# 7worden gesimuleerd door gebruik te maken van features die reeds aanwezig zijn. Echter, dit kan vervelende repeterende code opleveren.

De eerste makkelijke toepassing is het controleren van een gecaste variabele om die daarna te gebruiken. Voorheen werd dan gebruik gemaakt van de 'as' operator of van de 'is' en later nog een cast. Nu kunnen die twee dingen in een statement worden samengevoegd.

 

Pattern matching maakt het ook mogelijk om binnen een switch statement onderscheid te maken tussen object types in plaats van constanten. Op deze manier kunnen eenvoudig verschillende acties voor verschillende objecten ondernomen worden.

 

Bij een switch is het ook mogelijk om een extra guard clause op te nemen waarbij het mogelijk is om members van het type te pattern matchen of om extra controles uit te voeren.

 

Als je met een hiërarchische datastructuur zoals een tree te maken hebt, kan het heel krachtig zijn om hiermee recursief te matchen.

Features die het net niet gehaald hebben

Er zijn ook een aantal features die wel voorgesteld zijn voor C# 7 maar het (waarschijnlijk) niet halen in de uiteindelijke release. De kans is echter groot dat deze in C# 8 gaan komen. Daarom wil ik er hiervan van alsnog een aantal behandelen.

Records

Het komt vaak voor dat er een simpel data type zonder logica nodig is (POCO). Dan wordt meestal een class/struct gedefinieerd met een aantal auto-properties en eventueel een constructor om deze bij initialisatie te kunnen zetten. Dit heeft vrij veel syntactische overhead voor zoiets simpels. Om de syntax te vereenvoudigen stonden hiervoor record types op het C# 7-programma.

 

Samen met record types zou ook de pattern matching syntax verder uitgebreid worden. Zo zou eenvoudig op members van record types gematched kunnen worden;

Hier volgt een voorbeeld in het gebruik van pattern matching in combinatie met record types om een Expression te vereenvoudigen:

 

Non-Nullable Reference Types

In .NET is het bij een reference type mogelijk dat deze naar null verwijst. Dit zorgt er altijd voor dat code doorspekt is met null checks. Gelukkig is dit met de null-conditional operators ( ?. en ?[ ) al iets minder vervelend geworden. Het zou echter fijn zijn als afgedwongen kan worden dat een reference type niet null kan zijn. Eigenlijk net zoals bij een value type. Voor value types bestaat sinds .NET 2.0 al het concept van nullable value types, te herkennen aan het vraagteken.

int? i;

Het zou fijn zijn als value types zich net zo gedragen als reference types. In de ideale wereld zou bij een reference type ook met het vraagteken worden aangeven dat deze nullable is. Dit zou echter backwards compatibiliteit van de taal verstoren. Daarom is er het voorstel gedaan om met een uitroepteken aan te geven dat een ref type juist niet nullable is.

object! nonNullable;

Immutable types

Immutable types zijn types die na constructie niet meer aan te passen zijn. In het framework is een string daar een prototype voorbeeld van. Deze kan niet worden aangepast. Alle bewerkingen die je daarop doet leveren een nieuwe string op.

Een paar van de voordelen van immutable types zijn:

  • Inherent thread safe
  • Constante waarden kunnen parallel vanuit meerdere threads worden gelezen en dus gecached worden.

Het voorstel was om het immutable keyword te introduceren. Na constructie mag een class alleen read-only velden/properties hebben.