Met de nieuwe compiler die Microsoft ontwikkelt voor C# en Visual Basic wordt het eenvoudiger om nieuwe features aan de taal toe te voegen. Nu de compiler in de fase “technical preview” zit, hebben wij de mogelijkheid om te experimenteren met de nieuwe compiler en te zien welke features voor de volgende versie van C# te verwachten zijn. In het vorige artikel over dit onderwerp hebben we een reeks nieuwe features besproken. Inmiddels heeft het ontwikkelteam besloten om enkele features, die eerder “af” waren toch weer te schrappen. Geschrapt zijn “Declaration expressions” en “Primary constructors”. Maar het is mogelijk dat deze later alsnog weer opduiken. In ieder geval is het belangrijk om https://roslyn.codeplex.com/wikipage?title=Language%20feature%20status&referringTitle=Home in de gaten te houden.

Op deze lijst staan nog enkele features die de status “done” hebben en die we nog niet hebben besproken. Daarnaast is “string interpolation” toegevoegd. Wat dat is lees je in dit artikel.

Expression-bodied members

Met de komst van lambda expressies zijn we een beetje verwend geraakt als het gaat om het schrijven van functies en delegates. Veel rompslomp is verdwenen omdat we de aparte definities van delegates niet meer hoeven te schrijven.

Wat we voorheen als volgt moesten schrijven.

    class DelegateDemo
    {
        public delegate double DelegateCommissieSum(Commissie a, Commissie b);

        static double SumCommissie(Commissie a, Commissie b)
        {
            return a.Bedrag + b.Bedrag;
        }

        static void Run()
        {   
            DelegateCommissieSum sum = new DelegateCommissieSum(SumCommissie);
            Commissie c1 = new Commissie() { Bedrag = 10 };
            Commissie c2 = new Commissie() { Bedrag = 14 };
            double totaal = sum(c1, c2);
        }
    }

 

Kunnen we sinds C# 3.0 verkorten naar

DelegateCommissieSum sum2 = (ca, cb) => { return ca.Bedrag + cb.Bedrag; } ;

double totaal2 = sum2(c1, c2);

Het werd tijd om die verkorte schrijfwijze ook mogelijk te maken op de members van een type: zowel op methoden als op eigenschappen. Op deze manier hoeven methoden en eigenschappen die een hele kleine implementatie hebben niet meer voorzien te worden van accolades.

Voor methoden ziet dat er bijvoorbeeld zo uit:

public double BepaalKorting(double percentage) => (percentage / 100 * this.Bedrag);

maar het is ook mogelijk met operators

public static Prijsoperator +(Prijs p1, Prijs p2) => p1.Optellen(p2);

public static implicit operator string (Prijs p) => p.Valuta+ " " + p.Bedrag;

Natuurlijk kan je dit ook bij void methoden gebruiken:

public void Print() => Console.WriteLine(Valuta + " " + Bedrag);

En bij eigenschappen:

public string PrijsRegel => string.Format("{0} {1:C}", Valuta, Bedrag);

 

Voor indexers moet het ook gaan werken:

public Prijs this[int id] => store.LookupPrijs(id);

 

Voor de volledigheid staat de complete class met voorbeelden hieronder.

    public class Prijs
    {
        public string Valuta { get; set; }
        public double Bedrag { get; set; }

        public double BepaalKorting(double percentage) => (percentage / 100 * this.Bedrag);
        public static Prijs operator +(Prijs p1, Prijs p2) => p1.Optellen(p2);
        public static implicit operator string (Prijs p) => p.Valuta + " " + p.Bedrag;
        public void Print() => Console.WriteLine(Valuta + " " + Bedrag);
        public string PrijsRegel => string.Format("{0} {1:C}", Valuta, Bedrag);
        public Prijs this[int id] => store.LookupPrijs(id);

        public Prijs()
        { }

        public static Prijs PrijsMetKorting(Prijs origineel, double korting)
        {
            return new Prijs()
            {
                Bedrag = origineel.Bedrag * (1 - korting / 100),
                Valuta = origineel.Valuta
            };
        }

        public Prijs Optellen(Prijs commissie)
        {
            if (this.Valuta == commissie.Valuta)
                this.Bedrag += commissie.Bedrag;
            return this;
        }
    }

 

nameof operator

De nameof operator maakt het mogelijk om de variabele naam in een string te krijgen. Stel je voor dat je in een methode wilt valideren of een bepaalde parameter een waarde heeft gekregen.

Dat kan je als volgt doen.

public void GetRecept(string naam)
{
    if (string.IsNullOrEmpty(naam)) throw new ArgumentException("Geen waarde voor parameter naam");
    //...
}

Wanneer je echter besluit dat de parameter “naam” niet voldoet, en je maakt er via refactoring “titel” van. Dan klopt je exception-message niet meer. In zo’n geval is het handiger om gebruik te maken van de nameof() operator.

public void GetRecept(string naam)
{
    if (string.IsNullOrEmpty(naam)) throw new ArgumentException("Geen waarde voor parameter " + nameof(naam));
    //...
}

Zou je namelijk dan besluiten tot een wijziging van de parameter, dan verandert de exceptie vanzelf mee:

public void GetRecept(string titel)
{
    if (string.IsNullOrEmpty(naam)) throw new ArgumentException("Geen waarde voor parameter " + nameof(titel));
    //...
}

Zo kan er geen verwarring meer zijn wanneer tijdens runtime de methode zonder gevulde parameter wordt aangesproken.

 

#pragma

Het #pragma keyword kennen we in C# al sinds versie 2.0. In Visual Basic was er echter vergelijkbare optie om compiler directives mee te geven, bijvoorbeeld om standaard waarschuwingen uit te schakelen. Voor C# is de verandering relatief beperkt. Daar waar je voorheen alleen gebruik kon maken van de getallen, kun je nu ook de complete identifier toepassen.

Het onderstaande was sinds C# 2.0 al mogelijk.

#pragma warning disable 0168,0169

Maar in C# 6.0 kan je het ook zo doen.

#pragma warning disable CS0168,CS0169

 

String interpolation

Met de methode string.format is het al sinds C# 1.0 mogelijk om teksten te vullen met waarden van variabelen.

var tekst1 = string.Format("Het recept {0} duurt {1} minuten.", recept.Naam, recept.Duur);

Door op de juiste plaatsen placeholders in de tekst op te nemen worden deze tijdens runtime gevuld met de dan relevante teksten. Voor een relatief korte tekst of weinig variabelen is dat prima werkbaar. Maar naarmate het aantal variabelen in een tekst toeneemt, neemt de leesbaarheid af. En daarmee de kans op fouten ook. Het zou veel handiger zijn als we de variabelen een onderdeel zouden kunnen maken van de tekst, op de plek waar de waarde van die variabele moet komen. Met string interpolation is dat mogelijk.

var tekst2 = "Het recept \{recept.Naam} duurt \{recept.Duur} minuten.";

De schrijfwijze kan nog veranderen, maar functioneel komt het er op neer dat de waarde van de variabele tussen accolades tijdens runtime in de tekst komt te staan. Dat kan eventueel ook met formattering.

var tekst3 = "Het recept \{recept.Naam, 50} duurt \{recept.Duur : D4} minuten.";

Bovendien is deze feature niet beperkt tot variabelen.

var tekst4 = "Het recept duurt \{recept.Duur < 20 ? "minder" : "meer"} dan 20 minuten";

Je kunt er dus ook hele expressies in kwijt.

 

Conclusie

Het thema van C# is er niet één van grote veranderingen, en nieuwe manieren van werken. Daar hadden we wel mee te maken met de komst van Generics (C# 2.0), lambda expressies (C# 3.0), dynamic (C# 4.0) en asynchrone methoden (C# 5.0). In C# 6.0 zitten vooral handigheidjes. Kleine verbeteringen die het schrijven van code makkelijker, efficiënter en overzichtelijker maken.

In dit, en het vorige, artikel heb je gezien welke aanpassingen er nu in zitten. Het ontwikkelteam bij Microsoft zit in een afrondende fase. Er zal niet veel meer bij komen, en hopelijk wordt er naar aanleiding van testen niets meer geschrapt.

Een reeks uitgewerkte codevoorbeelden kan je hier vinden: https://github.com/sander-/Nieuw-in-C–6.0

Op de Roslyn-pagina https://roslyn.codeplex.com/ kan je de laatste versie van Visual Studio downloaden en proberen. Ook kan je er feedback kwijt over de nieuwe features.