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.
150 lines
6.6 KiB
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; }
|
|
}
|
|
}
|