C# 7.1 – Les nouveautés

Les nouveautés de C# 7.1 sont subtiles mais intéressante. Tout d’abord la sélection de la version du langage se fait dans les paramètres avancés du build. En effet, par défaut la version C# 7.1 n’est pas sélectionnée par défaut.

Il est également possible de modifier directement le fichier csproj en ajoutant un propertygroup approprié.

Async Main

Evolution, il est désormais possible d’utiliser le mot clé await dans la méthode Main. Il était en effet autrefois nécessaire d’encapsuler le retour d’une tâche asynchrone pour attendre le retour. Plusieurs techniques existaient entre la preview de l’Async CTP avec « GeneralThreadAffineContext », l’ « AsyncContext » du packge NuGet Nito.AsyncEX, c’est bien celle proposé par Microsoft la plus usité :

class Program
{
    static void Main(string[] args)
    {
        MainAsync(args).GetAwaiter().GetResult();
    }

    static async Task MainAsync(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

Avec C# 7.1, l’appel est nettement plus simple

class Program
{
    static async Task Main(string[] args)
    {
        Bootstrapper bs = new Bootstrapper();
        var list = await bs.GetList();
    }
}

Literal «default » et inférence de type

Le mot clé « default » est déjà particulièrement utile pour affecter une valeur par défaut à un géneric de type T dont on ne sait d’avance si c’est un type référence ou valeur. Ce mot clé peut par ailleurs être utilisé avec n’importe quel type managé comme default(string), default(int) ou default(int ?)

Avec C# 7.1, « default » peut être utilisé comme littéral si le compilateur peut faire un inférence de type. Autrement dit, au lieu d’écrire « default(T) », on peut littéralement écrire « defaut » si le compilateur a suffisamment d’information. Le code devient ainsi plus concis et clair ; cela marchant pour de nombreux cas comme la déclaration de valeurs par défaut de paramètre optionnel, le retour de méthodes, l’initialisation ou assignation de variables, etc .

public class Point
{
    public double X { get; }
    public double Y { get; }

    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }
}

public class LabeledPoint
{
    public double X { get; private set; }
    public double Y { get; private set; }
    public string Label { get; set; }

    // Providing the value for a default argument:
    public LabeledPoint(double x, double y, string label = default)
    {
        X = x;
        Y = y;
        this.Label = label;
    }

    public static LabeledPoint MovePoint(LabeledPoint source,
        double xDistance, double yDistance)
    {
        // return a default value:
        if (source == null)
            return default;

        return new LabeledPoint(source.X + xDistance, source.Y + yDistance,
        source.Label);
    }

    public static LabeledPoint FindClosestLocation(IEnumerable<LabeledPoint> sequence,
        Point location)
    {
        // initialize variable:
        LabeledPoint rVal = default;
        double distance = double.MaxValue;

        foreach (var pt in sequence)
        {
            var thisDistance = Math.Sqrt((pt.X - location.X) * (pt.X - location.X) +
                (pt.Y - location.Y) * (pt.Y - location.Y));
            if (thisDistance < distance)
            {
                distance = thisDistance;
                rVal = pt;
            }
        }

        return rVal;
    }

    public static LabeledPoint ClosestToOrigin(IEnumerable<LabeledPoint> sequence)
        // Pass default value of an argument.
        => FindClosestLocation(sequence, default);
}

Inférence du nom des éléments dans un type.

C# 7.0. a introduit les tuples. Lors de leur initialisation d’un tuple, les noms souhaités pour ses éléments sont généralement ceux des variables utilisés comme dans l’exemple suivant

string nom = "Fabrice JEAN-FRANCOIS";
int age = 26;
var personne = (nom: nom, age: age);

 

Avec C# 7.1, les noms d’éléments de tuple peuvent désormais être déduits à partir de variables utilisés :

string nom = "Fabrice JEAN-FRANCOIS";
int age = 26;
var personne = (nom, age); // le nom des elements du tuple seront « nom » et « age »

Génération d’assembly de référence

Le compilateur peut générer des assemblies de référénce uniquement via /refout et refonly.