You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mchsamples-.net-core/ex_008_005_pattern_matching/Program.cs

150 lines
6.6 KiB

// ========================================================================
//
// Copyright (C) 2017-2018 MARC CHEVALDONNE
// marc.chevaldonne.free.fr
//
// Module : Program.cs
// Author : Marc Chevaldonné
// Creation date : 2017-09-19
//
// ========================================================================
using System;
using static System.Console;
namespace ex_008_005_pattern_matching
{
class Program
{
static void Main(string[] args)
{
//C# 7.0 introduit le pattern matching, dont l'objectif est de permettre de "tester" si un objet respecte certaines conditions de "forme".
//En C# 7.0, on trouve pour le moment trois types de patterns :
// - constant patterns : qui permettent de tester si un objet est égal à une constante
// - type patterns : qui permettent de tester si un objet est de type T, et si c'est le cas, de le tester dans une nouvelle variable
// - var patterns : qui permettent de pacer un objet dans une nouvelle variable du même type
//Les patterns matching devraient certainement être beaucoup plus utilisés dans les versions futures de C#.
//Pour le moment, on en trouve deux cas d'utilisation majeurs : les expressions "is" et les clauses "case" dans les switch.
//PATTERN MATCHING AND IS-EXPRESSIONS
void DisplayPrice(object price)
{
//constant pattern dans une is-expression avec comparaison à null
if (price is null)
{
WriteLine("Vous avez rentré une valeur nulle");
return;
}
//var pattern dans une is-expression
if (price is var price2)
{
WriteLine($"price2 est de type : {price2.GetType().Name} ; price2 a pour valeur : {price2}");
}
//type pattern dans une is-expression avec comparaison à un type numérique
if (!(price is float p))
{
WriteLine($"price n'est pas du bon type. Type attendu : Single, Type utilisé : {price.GetType().Name}");
return;
}
WriteLine($"Vous avez rentré : {p:0.00} euros");
}
DisplayPrice(null);
DisplayPrice(32.0f);
DisplayPrice("coucou");
DisplayPrice(3);
//var-pattern : on a une copie des variables, donc attention aux types références !
void TestVarPattern(Nounours original)
{
WriteLine("Avant var pattern:");
WriteLine($"original : {original}");
if (original is var copie)
{
copie.Nom = "Chucky";
copie.NbPoils = 4;
}
WriteLine("Après var pattern:");
WriteLine($"original : {original}");
WriteLine($"copie : {copie}");
}
TestVarPattern(new Nounours { Nom = "Gizmo", NbPoils = 123456789, Naissance = new DateTime(1984, 6, 8) });
//PATTERN MATCHING DANS UN SWITCH AVEC DES CASES ET DES CONDITIONS SUPPLEMENTAIRES
Nounours[] nounours =
{
new Nounours { Nom = "Gizmo", NbPoils = 123456789, Naissance = new DateTime(1984, 6, 8) },
new NounoursProf { Nom = "Yoda", NbPoils = 4, Naissance = new DateTime(1980, 5, 21), Matière="How to become a Jedi?" },
new NounoursElève { Nom = "Ewok", NbPoils = 98989898, Naissance = new DateTime(1983, 5, 25), FormationSuivie="How to destroy an AT-ST?" },
new NounoursElève { Nom = "Chucky", NbPoils = 2, Naissance = new DateTime(1988, 11, 9), FormationSuivie="How to become naughty?" },
null
};
void TestPatternMatchingInASwitch(Nounours monNounours)
{
//Il est possible de faire un switch sur n'importe quel type désormais
//La nouvelle gestion du switch fait que maintenant, l'ordre des clauses "case" a de l'importance (dans l'exemple ci-dessous, si on mettait la 2ème avant la 1ère,
//la 1ère ne serait jamais exécutée). Heureusement, le compilateur vous aidera a trouvé les cas qui ne seront jamais exécutés !
switch (monNounours)
{
//type pattern avec une condition (when)
case NounoursElève élève when (élève.Naissance < new DateTime(1985, 1, 1)):
WriteLine($"{élève.Nom} est un vieil élève apprenant : {élève.FormationSuivie}");
break;
//type pattern sans condition
case NounoursElève élève:
WriteLine($"{élève.Nom} est un élève apprenant : {élève.FormationSuivie}");
break;
//type pattern
case NounoursProf prof:
WriteLine($"{prof.Nom} est un prof qui enseigne : {prof.Matière}");
break;
//même s'il y a un autre case plus bas (comme dans cet exemple), le default est toujours évalué en dernier, pour des raisons de compatibilité.
//Pour une meilleure lisibilité, ne faites donc pas comme dans cet exemple : laissez le default à la fin
default:
WriteLine($"{monNounours.Nom} est un Nounours comme un autre, sans histoire particulière...");
break;
//constant pattern
case null:
WriteLine($"Attention, ce Nounours est null ! (nom du paramètre : {nameof(monNounours)})");
break;
}
}
foreach (var n in nounours)
{
TestPatternMatchingInASwitch(n);
}
}
}
class Nounours
{
public string Nom { get; set; }
public int NbPoils { get; set; }
public DateTime Naissance { get; set; }
public override string ToString()
{
return $"{Nom} a {NbPoils} poils et est né en {Naissance.Year}";
}
}
class NounoursProf : Nounours
{
public string Matière { get; set; }
}
class NounoursElève : Nounours
{
public string FormationSuivie { get; set; }
}
}