Initialement prévu pour sortir en même temps que .Net Core 3.0, qui arrivera un peu plus tard cette année, C# 8.0 est finalement arrivé le mois dernier en même temps que Visual Studio 2019. En clair, si vous souhaitez tester toutes les nouveautés apportées par cette version, il vous faut soit installer Visual Studio 2019 ou bien la préversion de .Net Core 3.0. En attendant, voyons ensemble les quelques-unes des nouveautés les plus importantes


Les types références Nullables

Qui n’a jamais pesté devant un « System.NullReferenceException » qui vous fait planter tout un traitement ? Tout le monde j’ai envie de dire ! Et bien avec C# 8.0 c’est presque de l’histoire ancienne. Presque parce qu’il faudra tout de même faire un petit effort lors du développement. En effet, en activant les références nullables, le compilateur va tester toutes les variables avec un type non nullable et afficher un avertissement là où il y aura potentiellement une source d’erreurs.

Dans l’exemple ci-dessous, le programme va planter au moment d’afficher le nom complet du joueur car la variable prénom est à null.

class joueur
        {
            public string? nom { get; set; }
            public string? prenom { get; set; }

            public joueur(string sNom)
            {
                nom = sNom;
                prenom = null;
            }
        }
        static void Main(string[] args)
        {
            joueur joueur1 = new joueur("Neymar");

            Console.WriteLine(joueur1.nom.ToUpper() + " - " + joueur1.prenom.ToLower());

        }

Si on active les références nullables avec #nullable enable, on aura le droit à un petit avertissement visuel au niveau du code.

les nouveautés de c# 8.0

Il suffit ensuite d’un simple petit test pour faire disparaitre l’avertissement et surtout sécuriser son code.

if(joueur1.prenom != null && joueur1.nom != null)
            Console.WriteLine(joueur1.nom.ToUpper() + " - " + joueur1.prenom.ToLower());


Les flux asynchrones

On arrive au domaine qui met fait sans doute le plus mal à la tête : les flux asynchrones ! Maintenant, il est possible de créer des méthodes qui retournent un flux asynchrone et le consommer.

La méthode qui émet le flux doit respecter trois conditions :

  • être déclarée avec le modificateur « async »
  • retourner un objet de type IAsyncEnumerable<T>
  • contenir une instruction « yield return » pour pouvoir retourner des éléments consécutifs

Pour ensuite pouvoir consommer ce flux, il faut ajouter le mot-clé « await » devant une boucle « foreach » lorsqu’on énumère les différents éléments constitutifs du flux. Et puisqu’on on utilise le mot-clé « await », la méthode doit être déclarée avec le modificateur « async » et retourner un type d’objet autorisé comme Task ou Task<TResult>.

Je vous ai concocté un petit exemple ci-dessous qui simule l’évolution d’un téléchargement à l’écran. Rien de très compliqué, mais si vous avez la moindre question sur le code, n’hésitez pas à m’en faire part via les commentaires.

class Program
    {

        public static async IAsyncEnumerable<int> download()
        {
            for (int i = 1; i <= 100; i++)
            {
                Random rand = new Random();
                await Task.Delay(rand.Next(1,10)*100);
                yield return i;
            }
        }
        
        static async Task Main(string[] args)
        {
            await foreach (var number in download())
            {
                Console.Clear();
                Console.Write("Donwloading.... : "+number+"%");  
            }
        }
    }

Ce qui nous donne à l’exécution ceci :

c# 8 : exemple de flux asynchrone

Les Index et plages de données

Jouer avec les tableaux et leurs données, c’est ma grande passion et il y a pas mal de petites nouveautés de ce côté-là avec C # 8.0. Par exemple, il est maintenant possible de spécifier un index à partir de la fin à l’aide de l’opérande ^

Petit exemple :

  • pour récupérer le premier élément on doit faire : array[0] 
  • pour récupérer le dernier élément on doit faire : array[^1] 

Attention, si on utilise l’index « 0 » pour spécifier le premier élément d’un tableau, ça ne fonctionne pas de la même manière lorsqu’on part de la fin. En effet, «^0 » correspond à la fin du tableau, soit l’index qui suit le dernier élément. C’est surtout à utiliser lorsqu’on manipule des plages de données et non pas pour extraire une donnée.

Pour manipuler les plages, c’est tout aussi simple. Exemple avec un tableau de dix éléments :

  • pour récupérer les trois premiers éléments d’un tableau : array[0..3]
  • pour récupérer les trois derniers : array[8..11]

On peut aussi utiliser l’opérande ^ et faire les plages en partant de la fin :

  • pour récupérer les trois premiers : array[^8..^11]
  • pour récupérer les trois derniers : array[^3..^0]

Et si vous souhaitez récupérer l’intégralité des données : array[..]

Il est même possible de créer un objet Range et l’appliquer à un tableau :

Range troisPremiers = 0..3 ;
var test = array[troisPremiers] ;

Vous pouvez retrouver ci-dessous une petite compilation d’exemples de ce qu’on vient de voir

class Program
    {
        static void Main(string[] args)
        {
            var jours = new string[]
            {
               "lundi",
               "mardi",
               "mercredi",
               "jeudi",
               "vendredi",
               "samedi",
               "dimanche"
            };

            // Index
            Console.WriteLine("Premier élément : " + jours[0]);
            Console.WriteLine("Deuxiemme élément : " + jours[1]);
            Console.WriteLine("Dernier élément : " + jours[^1]);
            Console.WriteLine("Deuxiemme élément en partant de la fin: " + jours[^2]);
            Console.WriteLine();

            // Plages
            var first3 = jours[0..3]; // lundi, mardi, mercredi
            var last3 = jours[4..7]; // vendredi, samedi, dimanche

            var first3ByLast = jours[^7..^4]; //lundi, mardi, mercredi
            var last3ByLast = jours[^3..^0]; //vendredi, samedi, dimanche

            var tousLesJours = jours[..];

            Range mardiMercredi = 1..3;
            var marMer = jours[mardiMercredi]; // mardi, mercredi

            Console.WriteLine("Les trois premiers éléments sont : ");
            foreach (var item in first3)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine();

            Console.WriteLine("Les trois derniers éléments sont : ");
            foreach (var item in last3)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine();

            Console.WriteLine("Tous les éléments sont : ");
            foreach (var item in tousLesJours)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine();

        }
    }

L’expression Switch

Je termine mon article sur les nouveautés de C# 8.0 avec l’expression switch qui permet maintenant d’utiliser une syntaxe plus concise et avec moins de répétition de code. Mais comme il est difficile de vous expliquer cette nouvelle approche avec des mots, alors partons plutôt sur un exemple avec l’énumération Plateformes qui liste des plateformes de jeux :

 public enum Plateformes
        {
            Playstation,
            Xbox,
            Switch,
            PC,
            Stadia
        }

Dans mon  exemple, j’ai créé une méthode qui affiche la réaction d’un joueur fan de Sony, un Pro S pour les intimes, en fonction de la plateforme que je passe en paramètre. Et cette méthode utilise une expression switch.

 public static string ReactionJoueur(Plateformes plateforme) =>
         plateforme switch
            {
                Plateformes.Playstation =>  "La meilleur des consoles !!!!!!",
                Plateformes.Xbox => "Trop null, aucun interet",
                Plateformes.Switch => "C'est pour les enfants",
                Plateformes.PC => "Faut changer de carte graphique tous les six mois aussi",
                _ => "connais pas",
        };

Voyons les différences, améliorations et particularités lié à la syntaxe.

  • La variable se site avant le mot-clé switch. Ça permet ainsi de différencier l’expression de l’instruction qui reste par ailleurs toujours utilisable.
  • Les blocs case / break sont remplacé par =>
  • La clause default est remplacée par _
  • Les corps ne sont plus des instructions, mais des expressions

Et le Framework .Net 4.8 dans tout ça ?

Depuis que Microsoft a lancé .Net Core, qui a la particularité d’être une version open source, multiplateforme et évolutive de .Net, le Framework historique connait un développement en parallèle et surtout nettement plus lent. En effet, de par sa nature, .Net Core peut être amené à évoluer très rapidement et Microsoft ne peut pas et ne souhaite pas prendre le risque d’implémenter les différentes nouveautés sur le Framework .Net. Ce qui est particulièrement compréhensible lorsqu’on parle d’un environnement de développement qui est tout de même installé sur plus d’un milliard de machines. Malheureusement, à moins que Microsoft ne décide de changer ses plans, C# 8.0 n’est et ne devrait pas être implémenté dans le Framework .Net 4.8 L


Vous comprendrez que C# 8.0 ne se résume pas qu’à cette poignée de nouveautés et qu’il y a encore beaucoup de choses à découvrir. Je me suis cantonné à ces quelques exemples pour ne pas faire trop long, mais selon vos retours, je ferais bien une seconde partie avec d’autres cas concrets. Surtout que j’aimerais développé la partie .Net du site. En clair, c’est à vous de me dire.

Catégories : .Net

Marc

Développeur full-stack depuis maintenant près de 7 ans, j'ai décidé d'ouvrir ce blog afin de capitaliser mes acquis, essayer de partager mes connaissances, découvrir de nouvelles technologies et surtout échanger avec d’autres développeurs.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *