C# 7 est là !

Sortie avec le nouvel IDE de Microsoft, Visual Studio 2017, cette version de C# apporte une fois de plus des fonctionnalités qui vont vite devenir indispensables. D’autant plus que pour la première fois, Microsoft y a intégré des contributions de la communauté. Ce qui confirme sa volonté de s’impliquer d’avantage dans le monde de l’Open Source.

Les nouvelles features apportées dans cette nouvelle version, rendent le C# plus performant, plus lisible et plus fonctionnel. On peut noter d’ailleurs que Microsoft continue à enrichir le paradigme fonctionnel de son langage avec l’arrivé des fonctions locales, du pattern matching et l’amélioration des tuples.

Voyons tout ça d’un peu plus près…

Les tuples

Au delà des classes et des structures, les tuples sont des structures de données très légères qui vont permettrent de contenir plusieurs champs de représentation des données (de 1 à 8).

var position = (21, 50);
Console.WriteLine(position.Item1); //affiche 21
Console.WriteLine(position.Item2); //affiche 50

var coord = (Hor: 42, Ver: 100);
Console.WriteLine(coord.Hor); //affiche 42
Console.WriteLine(coord.Ver); //affiche 100

(int X, int Y) point = (84, 200);
Console.WriteLine(point.X); //affiche 84
Console.WriteLine(point.Y); //affiche 200

public (int Min, int Max) GetRange()
{
    return (168, 400);
}

var range = GetRange();
Console.WriteLine(range.Min); //affiche 168
Console.WriteLine(range.Max); //affiche 400

A noter

Pour les utiliser, il vous faudra utiliser le type System.ValueTuple, disponible dans le package NuGet du même nom.

Les déconstructeurs

Dans la continuité des tuples, le mécanisme de décomposition a été introduit. Non seulement, il fonctionne pour les tuples, mais aussi pour tous les types qui possède une méthode Deconstruct.

public 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 point = new Point(42, 100);

(int x1, int y1) = point;
Console.WriteLine(x1); //affiche 42
Console.WriteLine(y1); //affiche 100

var (x2, y2) = point;
Console.WriteLine(x2); //affiche 42
Console.WriteLine(y2); //affiche 100

Les fonctions locales

Les fonctions locales sont des méthodes déclarées dans d’autres méthodes. Elle ne sont accessibles que dans les scope des méthodes dans lesquelles elles sont déclarées, et peuvent avoir accès à tous les paramètres et les variables locales.

public int GetDoubleFactorialWithExtra(int number, int extra)
{
    int Factorial(int n)
    {
        return (n > 1) ? (n * Factorial(n - 1) + extra) : 1;
    }
    return Factorial(number) * 2;
}

var fact = GetDoubleFactorialWithExtra(5, 1);
Console.WriteLine(fact); //affiche 412

Le Pattern Matching

Le Pattern Matching ou « filtrage par motif »  permet de vérifier la correspondance d’une valeur avec un motif. Il est désormais possible d’utiliser l’opérateur is dans les if, l’opérateur when dans les switch/case, de déclarer puis affecter automatiquement une variable ces instructions conditionnelles. De plus, l’utilisation de n’importe quel type (et pas seulement des types primitifs) est possible.

object animal = new Dog();

if (animal is Dog dog)
    dog.Name = "D'Jenny";

switch (object)
{
    case string text:
        //do something
        break;
    case int number when number % 42 != 0:
        //do something
        break;
    case Cat cat when cat.Lives == 7:
        //do something
        break;
    case Dog dog:
        Console.WriteLine(dog.Name); //affiche D'Jenny
        break;
    case null:
        //do something
        break;
    default:
        //do something
        break;
}

Les variables out

Désormais, il n’y a plus besoin de déclarer une variable avant l’utilisation du modificateur de paramètres out. Elle peut être déclarée automatiquement lors de son utilisation.

string text = "42";

if (int.TryParse(text, out int number))
    Console.WriteLine(number); //affiche 42

if (int.TryParse(text, out var result) && result is int)
    Console.WriteLine(result); //affiche 42

Les membres sous forme d’expression

Les membres sous forme d’expression ou « expression-bodied members » ont été introduits par la version 6 de C#, mais seulement pour les méthodes et les propriétés readonly. Dorénavant, cette fonctionnalité est disponible sur les constructeurs, les destructeurs et les accesseurs get et set.

public class Person
{
    private string _name;

    public Person(string name) => Name = name;

    ~Person() => Console.WriteLine("Bye!");

    public string Name
    {
        get => name;
        set => Name = value;
    }
}

L’expression throw

Dans la continuité de la diversification des membres sous forme d’expression, Microsoft permet également d’utiliser l’instruction throw sous forme d’expression. Ce qui la rend utilisable dans les expressions conditionnelles.

var config = givenConfig ?? throw new InvalidOperationException();

Les types références non-nullables

Depuis la version 2 de C#, il était possible de rendre un type valeur nullable mais pas l’inverse. Maintenant, il est possible de forcer la non-nullabilité d’un type référence grâce au format abrégé T!, en introduisant le caractère « ! » après la déclaration du type.

int a; //type valeur non-nullable
int? b //type valeur nullable
string c; //type référence nullable
string! d //type référence non-nullable

Correction

Cette feature sera sûrement disponible dans la prochaine version de C# apparemment.

Les séparateurs digitaux

Dans un soucis de lisibilité des littéraux binaires, hexadécimaux et digitaux, il est désormais possible de séparer les chiffres grâce au caractère « _ », et ce n’importe où dans le littéral.

const int fortyTwoThousand = 42_000;

//0x pour une notation héxadécimale
const int fortyTwoThousand = 0x00_00_A4_10;

//0b pour une notation binaire
const int fortyTwoThousand = 0b1010_0100_0001_0000;

Conclusion

Microsoft a considérablement enrichi son langage de référence. Dans cette nouvelle version, le C# a un fois de plus gagné en lisibilité, en performance et en maturité, notamment en s’inspirant de fonctionnalités déjà présentent dans des langages fonctionnel comme le F#.

Cette évolution s’est fait de manière très rapide (moins d’un an et demi depuis C# 6), et promet à ce langage des améliorations modernes qui s’inscriront toujours dans l’air du temps.

Je vous invite d’ailleurs à jeter un coup d’oeil au projet Roslyn sur GitHub, aussi appelé « .NET Compiler Platform » qui illustre bien la volonté qu’a Microsoft de travailler en mode agile et d’inscrire sa place dans le monde de l’Open Source.

Il n'y a pas de commentaire pour l'instant.