.NET Core 2.0

La release 2.0 de .NET Core est désormais disponible, en ligne de commande, dans Visual Studio 2017 15.3 pour Windows et Mac. Comme précisé par Microsoft, il est prêt pour la production, sur vos propres machines ou dans le Cloud Azure, notamment Azure Web Apps.

En parallèle de cette release, le framework ASP.NET Core et Entity Framework, tous deux en 2.0, viennent également de sortir. Les spécificités de .NET Standard 2.0, quant à elles, sont également définies ; le set d’API disponible ayant doublé afin d’augmenter le nombre de projet pouvant cibler ce standard.

.NET Core 2.0 contient des améliorations substantielles en termes de performance et de Frameworks. Il supporte 6 nouvelles plateformes dont Debian Stretch, SUSE Linux Enterprise Server 12 SP2 et macOS High Sierra. Il considère par ailleurs Linux comme un OS, par architecture de microprocesseur, et qui fonctionne sur toutes les distributions ; du moins celles basées sur glibc notamment Debian, Red-Hat ; celles sur musl devant attendre.
Autre intérêt, .NET Core 2.0 supporte désormais des builds Linux et Windows ARM32.

.NET Core 2.0 utilise, sue macOS, les bibliothèques de chiffrement Apple et ne nécessite pas OpenSSL, contrairement à .NET Core 1.x

.NET Core 2.0 implémente par ailleurs .NET Standard 2.0 dont le nombre d’APIs disponible est passé de 13k à 32k.

C# 7.1

.NET Core 2.0 permet l’utilisation de C#7.1 et de ses nouveautés, principalement l’utilisation d’async sur la méthode Main et la déduction des noms de tuple/

Dans le détail

.NET Core 2 prend en charge .NET 2.0 standard ; lequel met à disposition plus de 20 000 API par rapport à .NET Standard 1.6. Ces API prennent en compte l’incorporation d’API .NET Framework et Xamarin dans .NET Standard.

Autre nouveauté importante, les bibliothèques de classes .NET Standard 2.0 peuvent faire appel à des bibliothèques .NET Framework sans nécessité de réécriture ou recompilation. Ceci est possible à condition que les bibliothèques .NET Framework appellent des API présentes dans .NET Standard.

Si vous ne faites pas le distingo entre .NET Core, .NET Standard et .NET Framework, voici quelques informations.

Ces trois termes peuvent perdre celle ou celui qui veult  retrouver dans l’écosystème .NET. Microsoft propose en effet 3 différentes visions de .NET.

dotNet

La vision .NET Framework correspond au framework de base, celui qui offre toutes les possibilités pour faire des applications de bureau ou web. Xamarin est la vision mobile (iOS , Android) ainsi que macOS.

.NET Core est la dernière vision. Opensource, disponible pour plusieurs OS; il permet la création d’applications de type console ainsi que d’applications Web de type ASP.NET Core ainsi que des services.

Reste maintenant à faire le distinguo entre .NET Core et .NET Standard

.NET Core

.NET Core est la dernière implémentation de  .NET et celle qui connaît le plus d’engouement ces derniers temps. Opensource, disponible pour plusieurs OS (Windows, macOS, Linux), .NET Core permet la construction d’applications ASP.NET Core Web, de services cloud et d’applications consoles. On espère beaucoup de .NET Core, la prochaine version (.NET Core 2.1) devrait apporter des améliorations comme les WebHooks, SignalR, support de Cosmos DB, orientation GDPR, etc.

.NET Core se distingue par une orientation interface de ligne de commande de prime abord. On parle de « first-class CLI » ( Command Line Interface).  Les commandes sont simples et puissantes, sans fioriture, on vise l’efficacité et des déploiements par simple en xcopy .

 

.NET Standard

.NET Standard vise un autre objectif ; celui de permettre aux développeur de construire des libraires qui peuvent être référencées dans toutes les implémentations de .NET,  c’est-à-dire .NET Framework, .NET Core et Xamarin.

En effet, .NET permet différentes cibles et la possibilité de partager du code, notamment des librairies entre toutes ces plateformes est un net avantage. Prenons le cas de Xamarin qui permet la création d’applications pour iOS, Android ainsi que des applications de type desktop pour macOS et comparons à .NET Core dont nous avons donné la définition précédemment. Vous l’aurez compris, aucun point commun… Si ce n’est le « .NET » mis devant.

Il est donc essentiel, lors de la création de librairies, d’être certains d’utiliser des APIs qui seront compatibles partout sans nécessité de réécriture. C’est le challenge de .NET Standard !

Notez, pour que cela fonctionne, qu’il faut expressément mettre en target .NET core ce qui n’est malheureusement pas le cas

 

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.