Microsoft livre un aperçu des nouveautés de C# 8.0
Et envisage de commencer à livrer cette version dans les préversions de Visual Studio 2019

Le , par Michael Guilloux, Chroniqueur Actualités
C# 8.0, la prochaine version majeure du langage C# de Microsoft est en préparation depuis un certain temps. Le plan de l'entreprise est que C# 8.0 soit livré en même temps que .NET Core 3.0. Toutefois, les fonctionnalités de la nouvelle version du langage commenceront à être livrées dans les préversions de Visual Studio 2019, la prochaine version majeure de l'EDI phare de Microsoft sur laquelle la firme travaille également.

En attendant, Microsoft a décidé de donner, dans un billet de blog, un aperçu des nouveautés de C# 8.0 pour permettre aux développeurs de savoir à quoi s'attendre.


Nouvelles fonctionnalités de C# 8.0

Types de références nullables

Les types de références nullables constituent l'une des fonctionnalités les plus importantes de C# 8.0. Le but de cette fonctionnalité est d'en finir avec les exceptions de référence null très fréquentes. Pour cela, elle vous empêche de mettre null dans des types de référence ordinaire comme string. Autrement dit, par défaut, ces types seront non nullables ! Mais vous pouvez faire en sorte qu’un type de variable soit nullable en vous servant de "?".

Cette fonctionnalité devrait donc casser le code existant. Un problème que Microsoft a décidé de gérer en douceur en générant des avertissements et non des erreurs. Toujours est-il qu'un code propre d'aujourd'hui pourra se retrouver avec des milliers d'avertissements demain. Vous devez donc choisir d'utiliser la fonctionnalité (ce que vous pouvez faire au niveau du projet, du fichier ou même de la ligne de code source).

Pour illustrer la fonctionnalité, le code suivant va générer un avertissement puisque vous essayez d'assigner un null à un type non nullable :

Code C# : Sélectionner tout
string s = null; // Warning: Assignment of null to non-nullable reference type

Si vous voulez le rendre null, vous pouvez utiliser le type de référence nullable associé, c'est-à-dire ici string? :

Code C# : Sélectionner tout
string? s = null; // Ok

Les flux asynchrones

La fonctionnalité async/wait de C# 5.0 vous permet d'utiliser (et de produire) des résultats asynchrones sous forme de code simple, sans callback. Toutefois, comme l'explique Microsoft, elle n'est pas très utile si vous souhaitez utiliser (ou produire) des flux continus de résultats, tels que ceux que vous pouvez obtenir d'un appareil IoT ou d'un service cloud. Les flux asynchrones sont donc là pour ça. Microsoft introduit IAsyncEnumerable<T>, qui correspond exactement à ce à quoi vous vous attendiez : une version asynchrone de IEnumerable<T>.

Code C# : Sélectionner tout
1
2
3
4
5
6
7
async IAsyncEnumerable<int> GetBigResultsAsync()
{
    await foreach (var result in GetResultsAsync())
    {
        if (result > 20) yield return result; 
    }
}

Les types Range et Index

Microsoft a ajouté un type Index, qui peut être utilisé pour l’indexation. Vous pouvez en créer un à partir d'un intqui permet de compter depuis le début, ou avec un opérateur de préfixe ^ qui permet de compter depuis la fin.

Code C# : Sélectionner tout
1
2
3
4
Index i1 = 3;  // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

Microsoft introduit également un type Range, composé de deux index, un pour le début et un pour la fin.

Code C# : Sélectionner tout
var slice = a[i1..i2]; // { 3, 4, 5 }

Autres nouveautés et dépendances de plateforme

C# introduit aussi les modèles récursifs (les modèles contenant d'autres modèles), et l'implémentation par défaut des membres d'une interface. Dans le dernier cas notamment, aujourd’hui, une fois que vous publiez une interface, vous ne pouvez pas ajouter de membres sans casser tous les implémenteurs existants, explique Microsoft. Dans C# 8.0, la firme vous permet de fournir un corps pour un membre d'interface. Ainsi, si quelqu'un n'implémente pas ce membre (peut-être parce qu'il n'était pas encore là quand il a écrit son code), il obtient simplement l'implémentation par défaut.

C# 8.0 viendra aussi avec les expressions Switch. Microsoft explique que les instructions Switch avec des modèles sont assez puissantes dans C# 7.0, mais peuvent être fastidieuses à écrire. Les expressions Switch viennent donc comme une version « légère », où tous les cas sont des expressions.

Une nouvelle fonctionnalité vous permettra d'omettre les types dans de nombreux cas. Lorsque vous créez un nouvel objet, le type est parfois déjà fourni à partir du contexte. Dans ces situations, le langage de Microsoft vous laissera omettre le type.

La plupart des fonctionnalités de C# 8.0 s’appliqueront à n’importe quelle version de .NET. Cependant, quelques-unes de ces fonctionnalités dépendent de certaines plateformes et seront spécifiques à .NET Standard 2.1. Il s'agit des flux asynchrones, des types Index et Range qui reposent tous sur de nouveaux types qui feront partie de .NET Standard 2.1. Si .NET Core 3.0 ainsi que Xamarin, Unity et Mono implémenteront complètement .NET Standard 2.1, .NET Framework 4.8 ne le fera pas. Cela signifie que les types requis pour utiliser ces fonctionnalités ne seront pas disponibles lorsque vous ciblerez C# 8.0 sur .NET Framework 4.8. Les implémentations par défaut des membres d’interface reposent aussi sur de nouvelles améliorations de runtime, et Microsoft ne les apportera pas non plus dans .NET Runtime 4.8. Donc, cette fonctionnalité ne fonctionnera tout simplement pas sur .NET Framework 4.8 et sur les anciennes versions de .NET.

Source : Blog Microsoft

Et vous ?

Que pensez-vous des nouveautés de C# 8.0 et du fait que certaines ne fonctionneront pas sur .NET Framework 4.8 ?
Qu'attendez-vous encore comme fonctionnalités dans le langage de Microsoft ?

Voir aussi :

Visual Studio Code 1.29 est disponible : aperçu des nouveautés dans l'éditeur de code open source et multiplateforme de Microsoft
Microsoft livre un aperçu des changements de l'expérience et l'interface utilisateur dans Visual Studio 2019, la prochaine version majeure de son EDI
Microsoft annonce que ASP.NET Core 3.0 fonctionnera uniquement sur .NET Core 3.0 et ne sera plus compatible avec la plateforme .NET Framework
Project Roslyn : comment Microsoft a réécrit son compilateur C# en C# et l'a rendu open source, le lead designer du langage raconte l'histoire
MonoGame, le framework C# pour le développement de jeux vidéo arrive en version 3.7


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse Signaler un problème

Avatar de CS FS CS FS - Membre habitué https://www.developpez.com
le 14/11/2018 à 14:28
Que va-t-il advenir de string.IsNullOrWhiteSpace() ?
Oui, je me pose des questions existentielles.
Avatar de stailer stailer - Membre chevronné https://www.developpez.com
le 14/11/2018 à 16:59
Que va-t-il advenir de string.IsNullOrWhiteSpace() ?
Je pense que c'est toujours utile car comme son nom l'indique ça vérifie aussi si ta chaîne n'est pas constituée que d'espaces blancs
Avatar de J@ckHerror J@ckHerror - Membre expérimenté https://www.developpez.com
le 14/11/2018 à 17:18
Citation Envoyé par stailer Voir le message
Je pense que c'est toujours utile car comme son nom l'indique ça vérifie aussi si ta chaîne n'est pas constituée que d'espaces blancs
Comme CS_FS je me pose des questions existancielles !
Ok pour WhiteSpace ! Mais quid de IsNullOrEmpty() ?

Sinon je valide les évolutions mais je suis pas fan d'omettre les types, je minimise l'utilisation des var , quasis que pour des tests ponctuels, je trouve ça inutile et vraiment pas pratique lors de la reprise de code ou lors de débogage.

J@ck.
Avatar de Kikuts Kikuts - Membre éclairé https://www.developpez.com
le 14/11/2018 à 17:21
L'article ne parle pas des interfaces qui pourront porter une implémentation de base ????!!!!
Pourtant c'est une des features que je préfère !

Exemple (codé sans passer par IDE dsl)

Code : Sélectionner tout
1
2
3
4
5
6
7
interface IViewModel : INotifyPropertyChanged
{
 void RaisePropertyChanged(string propertyName)
{
    PropertyChanged?.invoke(propertyName);
}
}
Avatar de tatayo tatayo - Expert éminent https://www.developpez.com
le 14/11/2018 à 17:37
J'ai un petit problème avec l'implémentation par défaut dans une interface.
C# n'implémente pas l'héritage multiple, car "on ne sait pas quoi faire si une classe hérite de 2 classes qui implémentent la même méthode".

Quid d'une classe qui hérite de 2 Interfaces qui implémentent la même méthode ? On se retrouve avec le même "problème".

Concernant le "range", le point qui me chagrine est que le comptage part de 0 au début de la chaine, et de 1 à la fin.
Code C# : Sélectionner tout
1
2
3
4
5
 
Index i1 = 1;  // number 1 from beginning
Index i2 = ^1; // number 1 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "1, 9"

Dans cet exemple, l'indice 1 est le second caractère, et l'indice ^1 le dernier. Pourquoi ce n'est pas ^0 ?

Tatayo.
Avatar de Noxen Noxen - Membre éclairé https://www.developpez.com
le 14/11/2018 à 17:43
Citation Envoyé par Kikuts Voir le message
L'article ne parle pas des interfaces qui pourront porter une implémentation de base ????!!!!
Pourtant c'est une des features que je préfère !

Exemple (codé sans passer par IDE dsl)

Code : Sélectionner tout
1
2
3
4
5
6
7
interface IViewModel : INotifyPropertyChanged
{
 void RaisePropertyChanged(string propertyName)
{
    PropertyChanged?.invoke(propertyName);
}
}
Ça c'est justement un cas où ça me paraîtrait inapproprié. D'un point de vue fonctionnel un IViewModel ne devrait pas permettre à son consommateur de lever lui-même l'événement, après tout seul le ViewModel peut dire si une de ses propriétés à réellement changé sa valeur (puisqu'il pourrait par exemple bloquer l'affectation d'une valeur invalide). Ce genre de méthode n'a ça place que dans la structure interne d'une classe et ne devrait pas être dans une interface. Si on veut factoriser ce code on le ferait dans une classe de base (éventuellement abstract) qui serait héritée par d'autres classes spécifiques. En revanche on pourrait avoir, j'imagine, une méthode GetModelVersion(), qui donnerait des informations sur le modèle de données sous-jacent, et renverrait une valeur par défaut si ce n'est pas géré par une implémentation spécifique.

En outre il me semble que ce mécanisme devait être introduit pour permettre de faire évoluer une interface sans introduire de breaking change auprès des "implémenteurs" (qui autrement ne seraient plus compatibles avec leurs propres consommateurs). Il me semble que l'utiliser pour factoriser du code constitue un peu un détournement de l'intention de départ.
Avatar de Iradrille Iradrille - Expert confirmé https://www.developpez.com
le 14/11/2018 à 20:27
Ces références nullables sont les bienvenues, mais peuvent mener à des trucs lourds / contre-intuitifs..

Code C# : Sélectionner tout
1
2
3
4
5
6
7
8
9
string? str = "blah";
 
if(!string.IsNullOrEmpty(str) { Console.Out.WriteLine(str.Length); } // utilisation comme une ref "classique" ?
if(!string.IsNullOrEmpty(str?.Value)) { Console.Out.WriteLine(str.Value.Length); } // ou comme un Nullable<T> ?
 
int foo = null; // erreur
string bar = null; // warning
 
if(bar == null) { } // vrai ? faux ? erreur ? warning ?
Avatar de miaous miaous - Membre habitué https://www.developpez.com
le 14/11/2018 à 20:37
Citation Envoyé par tatayo Voir le message
J'ai un petit problème avec l'implémentation par défaut dans une interface.
C# n'implémente pas l'héritage multiple, car "on ne sait pas quoi faire si une classe hérite de 2 classes qui implémentent la même méthode".

Quid d'une classe qui hérite de 2 Interfaces qui implémentent la même méthode ? On se retrouve avec le même "problème".

Tatayo.
en java, si une classe implémente 2 interface qui definisse la même méthode par défaut. Il faut implémente obligatoirement dans la classe.
Il doit avoir le même cas en c#
Avatar de Pol63 Pol63 - Expert éminent sénior https://www.developpez.com
le 14/11/2018 à 20:43
Citation Envoyé par tatayo Voir le message
Quid d'une classe qui hérite de 2 Interfaces qui implémentent la même méthode ? On se retrouve avec le même "problème".
ca ne change pas grand chose je pense, enfin quand tu implémentes 2 interfaces avec une méthode de même nom et même signature il fallait déjà spécifier
ca reviendra au même je pense, enfin ce n'est pas précisé oui, car j'ai cru comprendre que ce n'était pas un override mais bien une récupération implicite, donc il faudrait pouvoir en réorienter une alors qu'aucune des 2 n'apparaitra ...

Citation Envoyé par tatayo Voir le message
Concernant le "range", le point qui me chagrine est que le comptage part de 0 au début de la chaine, et de 1 à la fin.
Dans cet exemple, l'indice 1 est le second caractère, et l'indice ^1 le dernier. Pourquoi ce n'est pas ^0 ?
il faut plus le voir comme un count - n donc count - 1 ramène bien à la fin

Citation Envoyé par Noxen Voir le message
Ça c'est justement un cas où ça me paraîtrait inapproprié. D'un point de vue fonctionnel un IViewModel ne devrait pas permettre à son consommateur de lever lui-même l'événement, après tout seul le ViewModel peut dire si une de ses propriétés à réellement changé sa valeur (puisqu'il pourrait par exemple bloquer l'affectation d'une valeur invalide). Ce genre de méthode n'a ça place que dans la structure interne d'une classe et ne devrait pas être dans une interface. Si on veut factoriser ce code on le ferait dans une classe de base (éventuellement abstract) qui serait héritée par d'autres classes
l'appel à RaisePropertyChanged restera dans la classe sur chaque propriété, donc c'est bien la classe qui saura s'il faut lever l'event (au passage avec [CallerMemberName] ca évite de préciser le nom de la propriété)
après passer par une classe type ObservableObject pour en hériter ca n'est pas toujours possible, en wpf par exemple on a souvent envie d'hériter de dependencyobject, donc avoir une interface avec du code ca amène quand même un peu de souplesse

après libre à chacun d'utiliser ou non
moi c'est l'object nullable que je vois pas trop les cas d'utilisations
Avatar de François DORIN François DORIN - Responsable .NET & Magazine https://www.developpez.com
le 14/11/2018 à 22:34
Citation Envoyé par miaous Voir le message
en java, si une classe implémente 2 interface qui definisse la même méthode par défaut. Il faut implémente obligatoirement dans la classe.
Il doit avoir le même cas en c#
En C#, il est possible d'implémenter un membre d'une interface de manière implicite ou explicite. En cas de présence de deux implémentations, il serait possible d'avoir un code qui compile, mais il serait alors obligatoire de préciser l'interface utilisée lors de l'appel à la méthde, pour savoir quelle version utilisée. Je n'ai pas regardé en détail au niveau de ce cas, donc je ne sais pas si c'est supporté. Mais c'est une possibilité.

Au sujet des références nullables, je ne suis pas contre sur le principe. Cela peut permettre d'éclaircir le code. Par contre, ce que je trouve dommage, c'est que c'est un changement générant une incompatibilité avec le code déjà existant. Un point fort de C# jusqu'à présent était sa compatibilité et sa pérennité (qui en prennent un coup pour le coup).

Si .NET Core 3.0 ainsi que Xamarin, Unity et Mono implémenteront complètement .NET Standard 2.1, .NET Framework 4.8 ne le fera pas.
Cette phrase est trompeuse car sous-entend que .NET Framework 4.8 implémentera partiellement .NET Standard 2.1. Certains ajouts de C#8 ne seront pas supportés par le framework 4.8 car il ne sera pas compatible .NET Standard 2.1. Ce n'est pas une compatibilité "à la carte" où le framework .NET 4.8 implémenterait de manière partielle .NET Standard 2.1. Le framework .NET 4.8 implémentera uniquement .NET Standard 2.0, et comme certaines fonctionnalités de C#8 dépendront de type introduit par la version 2.1, ces fonctionnalités ne seront donc pas présentes.

Ce choix a été fait pour des raisons de compatibilité justement et pour ne pas risquer de casser des programmes existants, car certaines de ces fonctionnalités nécessitent une mise à jour du CLR.
Contacter le responsable de la rubrique Accueil