Microsoft annonce la disponibilité de .NET Core 3 Preview 2 et apporte les expressions switch avec C# 8
Ainsi que d'autres améliorations

Le , par Stéphane le calme

186PARTAGES

13  0 
Utiliser les déclarations

Êtes-vous fatigué d'utiliser des instructions qui nécessitent d'indenter votre code? Vous pouvez maintenant écrire le code suivant, qui attache une déclaration à la portée du bloc d'instructions actuel, puis dispose de l'objet à la fin de celui-ci.

Code : Sélectionner tout
1
2
3
4
5
6
static void Main(string[] args) 
{ 
    using var options = Parse(args); 
    if (options["verbose"]) { WriteLine("Logging..."); } 
 
} // options disposed here
Les expressions Switch

Quiconque utilise C # aime probablement l’idée d’une instruction switch, mais pas la syntaxe. Le C # 8 introduit les expressions switch, qui activent les fonctions suivantes: la syntaxe terser, renvoie une valeur puisqu'il s'agit d'une expression et qu'il est entièrement intégré à la correspondance de modèle. Le mot clé switch est "infixe", ce qui signifie que le mot clé se situe entre la valeur testée (ici, c’est o) et la liste des cas, de la même manière que l’expression lambdas. Les exemples suivants utilisent la syntaxe lambda pour les méthodes, qui s’intègre bien avec les expressions switch mais n’est pas obligatoire.

Vous pouvez voir la syntaxe des expressions switch dans l'exemple suivant:

Code : Sélectionner tout
1
2
3
4
5
6
static string Display(object o) => o switch 
{ 
    Point { X: 0, Y: 0 }         => "origin", 
    Point { X: var x, Y: var y } => $"({x}, {y})", 
    _                            => "unknown" 
};
Il y a deux modèles en jeu dans cet exemple. o correspond d’abord au modèle de type Point, puis au modèle de propriété à l’intérieur des {accolades}. Le _ décrit le modèle de suppression, qui est identique à celui par défaut pour les instructions switch.

Vous pouvez aller plus loin et vous fier à la déconstruction des tuples et à la position des paramètres, comme vous pouvez le constater dans l'exemple suivant:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
static State ChangeState(State current, Transition transition, bool hasKey) => 
    (current, transition) switch 
    { 
        (Opened, Close)              => Closed, 
        (Closed, Open)               => Opened, 
        (Closed, Lock)   when hasKey => Locked, 
        (Locked, Unlock) when hasKey => Closed, 
        _ => throw new InvalidOperationException($"Invalid transition") 
    };
Dans cet exemple, vous pouvez constater qu'il n'est pas nécessaire de définir une variable ou un type explicite pour chacun des cas. Au lieu de cela, le compilateur peut faire correspondre le tuple à tester avec les n-uplets définis pour chacun des cas.

Tous ces modèles vous permettent d'écrire un code déclaratif qui capture votre intention au lieu d'un code procédural implémentant des tests. Le compilateur devient responsable de la mise en œuvre de ce code de procédure ennuyeux et il est garanti qu'il le fera toujours correctement.

Il y aura toujours des cas où les instructions switch seront un meilleur choix que les expressions switch et les modèles peuvent être utilisés avec les deux styles de syntaxe.

Nouvelles API Math

  • BitIncrement / BitDecrement : correspond aux opérations IEEE nextUp et nextDown. Elles renvoient le plus petit nombre à virgule flottante qui se compare plus ou moins à l'entrée (respectivement). Par exemple, Math.BitIncrement (0.0) renverrait double.Epsilon.
  • MaxMagnitude / MinMagnitude : correspond aux opérations IEEE maxNumMag et minNumMag; elles renvoient la valeur supérieure ou inférieure en magnitude aux deux entrées (respectivement). Par exemple, Math.MaxMagnitude (2.0, -3.0) renverrait -3.0.
  • ILogB : correspond à l'opération logB IEEE qui renvoie une valeur intégrale, elle renvoie le journal intégral en base 2 du paramètre d'entrée. C'est effectivement la même chose que floor (log2 (x)), mais avec un minimum d'erreur d'arrondi.
  • ScaleB : correspond à l'opération scaleB IEEE qui prend une valeur intégrale, elle renvoie effectivement x * pow (2, n), mais avec une erreur d'arrondi minimale.
  • Log2 : correspond à l'opération log2 IEEE, renvoie le logarithme en base 2. Cela minimise les erreurs d'arrondi.
  • FusedMultiplyAdd : correspond à l'opération fma IEEE, il effectue une addition multipliée fusionnée. C'est-à-dire qu'il effectue (x * y) + z en une seule opération, minimisant ainsi l'erreur d'arrondi. Un exemple serait FusedMultiplyAdd (1e308, 2.0, -1e308) qui renvoie 1e308. La valeur régulière (1e308 * 2.0) - 1e308 renvoie double.PositiveInfinity.
  • CopySign : correspond à l'opération copySign IEEE, il renvoie la valeur de x, mais avec le signe de y.



Utf8JsonWriter

Utf8JsonWriter fournit un moyen hautement performant, non mis en cache, d’écrire du texte JSON codé en UTF-8 à partir de types .NET courants tels que String, Int32 et DateTime. Comme le reader, le writer est un type fondamental, de bas niveau, qui peut être utilisé pour créer des sérialiseurs personnalisés. L'écriture d'une charge JSON à l'aide du nouvel utilitaire Utf8JsonWriter est 30 à 80% plus rapide que l'utilisation de l'enregistreur de Json.NET et ne l'alloue pas.

Voici un exemple d'utilisation de Utf8JsonWriter qui peut être utilisé comme point de départ:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
static int WriteJson(IBufferWriter output, long[] extraData) 
{ 
    var json = new Utf8JsonWriter(output, state: default); 
 
    json.WriteStartObject(); 
 
    json.WriteNumber("age", 15, escape: false); 
    json.WriteString("date", DateTime.Now); 
    json.WriteString("first", "John"); 
    json.WriteString("last", "Smith"); 
 
    json.WriteStartArray("phoneNumbers", escape: false); 
    json.WriteStringValue("425-000-1212", escape: false); 
    json.WriteStringValue("425-000-1213"); 
    json.WriteEndArray(); 
 
    json.WriteStartObject("address"); 
    json.WriteString("street", "1 Microsoft Way"); 
    json.WriteString("city", "Redmond"); 
    json.WriteNumber("zip", 98052); 
    json.WriteEndObject(); 
 
    json.WriteStartArray("ExtraArray"); 
    for (var i = 0; i < extraData.Length; i++) 
    { 
        json.WriteNumberValue(extraData[i]); 
    } 
    json.WriteEndArray(); 
 
    json.WriteEndObject(); 
 
    json.Flush(isFinalBlock: true); 
 
    return (int)json.BytesWritten; 
}
Utf8JsonWriter accepte IBufferWriter comme emplacement de sortie dans lequel les données JSON doivent être écrites de manière synchrone et vous, en tant qu’appelant, devez fournir une implémentation concrète. La plateforme n'inclut pas actuellement d'implémentation de cette interface, mais Microsoft prévoit d'en fournir une qui s'appuie sur un tableau d'octets redimensionnable. Cette implémentation permettrait des écritures synchrones, qui pourraient ensuite être copiées dans n’importe quel flux (de manière synchrone ou asynchrone). Si vous écrivez du JSON sur le réseau et que vous incluez le package System.IO.Pipelines, vous pouvez utiliser l'implémentation basée sur Pipe de l'interface appelée PipeWriter pour éviter de copier le JSON d'un tampon intermédiaire dans la sortie réelle.

Vous pouvez vous inspirer de cet exemple d'implémentation de IBufferWriter . Ce qui suit est une implémentation concrète d'un squelette d'interface basée sur un tableau :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class ArrayBufferWriter : IBufferWriter, IDisposable 
{ 
    private byte[] _rentedBuffer; 
    private int _written; 
 
    public ArrayBufferWriter(int initialCapacity) 
    { 
        // TODO: argument validation 
 
        _rentedBuffer = ArrayPool.Shared.Rent(initialCapacity); 
        _written = 0; 
    } 
 
    public void Advance(int count) 
    { 
        // TODO: check if disposed 
 
        // TODO: argument validation 
 
        _written += count; 
    } 
 
    public Memory GetMemory(int sizeHint = 0) 
    { 
        // TODO: check if disposed 
 
        // TODO: argument validation 
 
        // TODO: grow/resize the buffer as needed based on your resizing strategy 
 
        return _rentedBuffer.AsMemory(_written); 
    } 
 
    public Span GetSpan(int sizeHint = 0) 
    { 
        // TODO: check if disposed 
 
        // TODO: argument validation 
 
        // TODO: grow/resize the buffer as needed based on your resizing strategy 
 
        return _rentedBuffer.AsSpan(_written); 
    } 
 
    public void Dispose() 
    { 
        // return back to the pool 
    } 
}
JsonDocument

Dans la Preview 2, Microsoft a également ajouté System.Text.Json.JsonDocument qui a été construit sur le lecteur Utf8JsonReader. JsonDocument permet d'analyser des données JSON et de créer un DOM (Document Object Model) en lecture seule pouvant être interrogé pour prendre en charge l'accès et l'énumération aléatoires. Les éléments JSON qui composent les données sont accessibles via le type JsonElement exposé par le JsonDocument en tant que propriété appelée RootElement. JsonElement contient les énumérateurs de tableau et d'objet JSON, ainsi que des API permettant de convertir du texte JSON en types .NET courants. L’analyse d’une charge JSON typique et l’accès à tous ses membres à l’aide de JsonDocument sont deux à trois fois plus rapides que Json.NET, avec très peu d’allocations pour des données de taille raisonnable (<1 Mo).

Voici un exemple d'utilisation de JsonDocument et de JsonElement pouvant être utilisé comme point de départ:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static double ParseJson() 
{ 
    const string json = " [ { \"name\": \"John\" }, [ \"425-000-1212\", 15 ], { \"grades\": [ 90, 80, 100, 75 ] } ]"; 
 
    double average = -1; 
 
    using (JsonDocument doc = JsonDocument.Parse(json)) 
    { 
        JsonElement root = doc.RootElement; 
        JsonElement info = root[1]; 
 
        string phoneNumber = info[0].GetString(); 
        int age = info[1].GetInt32(); 
 
        JsonElement grades = root[2].GetProperty("grades"); 
 
        double sum = 0; 
        foreach (JsonElement grade in grades.EnumerateArray()) 
        { 
            sum += grade.GetInt32(); 
        } 
 
        int numberOfCourses = grades.GetArrayLength(); 
        average = sum / numberOfCourses; 
    } 
 
    return average; 
}
Source : Microsoft

Voir aussi :

De .NET Core 1 à .NET Core 3.0, retour sur l'évolution du Framework open source et multiplateforme de Microsoft
ASP.NET Core 2.2 est disponible en version stable avec un nouveau module d'hébergement dans IIS et une nouvelle API pour suivre l'état des apps
La version 2.2 du framework .Net Core est disponible avec l'ajout de sécurité pour les connexions avec SQL Server et un meilleur suivi des services

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de rt15
Membre confirmé https://www.developpez.com
Le 11/02/2019 à 17:40
Pardon mais en première lecture j'ai trouvé ces résultats suffisamment surprenant pour me demander si c'était pas pondu par une boîte, comment dire, légèrement influencée par M$.
Genre une boîte qui vend des produits basés sur ASP.NET et qui est toute contente d'avoir comme par hasard choisi la meilleur technologie.

Pour remettre dans le contexte, il y a quelques années, je me suis un peu intéressé à nodejs.
Avant cette étude, j'imaginais qu'un serveur en nodejs devais être au mieux 20 ou 30% plus lent qu'un serveur en C, C++ ou en Java.
Généralement le javascript peut difficilement espérer faire mieux, même exécuté par le V8 de Google qui est utilisé par nodejs.

Je me disais que les utilisateurs de nodejs acceptaient cette perte de performance.
Mais en fait pas du tout.
L'architecture d'un serveur nodejs est bien différente de la plupart des serveurs de l'époque.
Alors que beaucoup utilisaient (et utilisent encore) un thread par requête HTTP et parallélisaient les traitements sur différents coeurs, nodejs utilise un seul thread (du point de vue du développeur JS) et se base sur les entrées sorties asynchrones.

Le coeur de nodejs, c'est libuv, une bibliothèque écrite en C par le créateur de nodejs.
Cette librairie permet avant tout de faire en asynchrone les I/O sur les sockets et les disques.

En gros le thread principal ne fait que soumettre des demandes de "tâches" au système d'exploitation, du genre écrit moi ça sur telle socket.
Mais le thread n'attends pas la fin de la lecture ou de l'écriture : la demande de l'exécution d'une tâche n'est pas bloquante.
Au lieu de cela, le thread principal se met en attente sur un ensemble d’évènements tels que "fin de l'écriture" ou "il y a quelque chose à lire sur tel socket".
Le système réalise les tâches en arrière plan et notifie quand elles sont terminées.
Dès qu'un événement se déclenche, le thread principal va le traiter, généralement en soumettant de nouvelles tâches d'entrée/sortie, puis se remettre en attente d'un nouvel évènement.
De cette manière le thread principal a "très peu" de travail et peut gérer des quantités astronomiques de connections et de lectures/écritures sur disque.
Le fait d'avoir peu de threads est très avantageux par rapport à un serveur classique car quand le processeur change de thread, il faut qu'il remplace son contexte d'exécution et ça prend un certain temps.
Ce contexte et la pile associée au thread prend aussi de la place en mémoire.
Par contre le désavantage d'avoir un seul thread principal est que si on a besoin de faire une tâche gourmande en CPU et qu'on l'a fait en JS, ça va bloquer le thread principal et le serveur ne fera rien d'autre : il ne sera pas à l'écoute des évènements pendant ce temps là.

Le résultat c'est que pour certaines applications, un serveur nodejs ne vas pas être 20 ou 30% plus lent qu'une appli JEE. Le serveur nodejs peut battre le JEE à plate couture.
Mais ce n'est pas JS qui est plus rapide que le Java. C'est la librairie C libuv qui bat l'archi JEE.

Donc sachant la qualité de l'approche et de l'implémentation de nodejs dans ce domaine, j'ai été surpris que aspcore puisse écraser nodejs sur un "Best plaintext responses per second".

Qu'est ce qui peut expliquer une telle différence ?
En y regardant de plus près, a priori, le serveur web utilisé par ASP.NET Core dans ce benchmark s'appelle Kestrel (c'est celui par défaut).
https://github.com/TechEmpower/Frame...rks/Program.vb
(à noter qu'ils ont implémentés le benchmark en VB, pas en C#!)

Et devinez sur quoi est basé Kestrel à la base ? Sur libuv...

Depuis l'utilisation de libuv a été supprimé mais en fin de compte la nouvelle implémentation se base certainement sur epoll sous Linux et les Overlapped I/O sous Windows.
Kestrel s'appuie donc sur les mêmes fonctions systèmes que libuv.

En tout cas chapeau aux développeurs C/C++ de M$ pour leur résultat sur ce bench.
1  0 
Avatar de chavers
Nouveau membre du Club https://www.developpez.com
Le 01/03/2019 à 10:19
En effet, dire que libUV est plus rapide sur aspcore que sur nodejs semble étrange... Mais bon, c'est un bench l'interprétation reste humaine. Si je regarde la même source, je peux conclure que PHP est plus rapide que aspcore pour sérialiser du json et que sur les 100 premiers du test « fortunes » les deux seuls qui génèrent des erreurs sont sur aspcore. De là à dire que aspcore est lent et buggé, il n'y a qu'un pas ... de troll.
0  0 
Avatar de ryankarl65
Membre actif https://www.developpez.com
Le 18/03/2019 à 2:47
J'aurais bien aime avoir un comparatif avec les solutions existantes.
Merci pour cette article.
0  0 

 
Contacter le responsable de la rubrique Accueil

Partenaire : Hébergement Web