Correspondance des modèles : les is
expressions et switch
les opérateurs and
, or
et not
dans les modèles
Vous utilisez l’expression, l’instruction is
switch et l’expression switch pour faire correspondre une expression d’entrée à un nombre quelconque de caractéristiques. C# prend en charge plusieurs modèles, notamment la déclaration, le type, la constante, la relation, la propriété, la liste, var et discard. Les modèles peuvent être combinés à l’aide des mots clés logiques booléens and
, or
et not
.
Les expressions et instructions C# suivantes prennent en charge les critères spéciaux :
Dans ces constructions, vous pouvez faire correspondre une expression d’entrée à l’un des modèles suivants :
- Modèle de déclaration : pour vérifier le type d’exécution d’une expression et, si une correspondance réussit, affecter un résultat d’expression à une variable déclarée.
- Modèle de type : pour vérifier le type d’exécution d’une expression.
- Modèle constant : pour tester qu’un résultat d’expression est égal à une constante spécifiée.
- Modèles relationnels : pour comparer un résultat d’expression avec une constante spécifiée.
- Modèles logiques : pour tester qu’une expression correspond à une combinaison logique de modèles.
- Modèle de propriété : pour tester que les propriétés ou les champs d’une expression correspondent aux modèles imbriqués.
- Modèle positionnel : pour déconstruire un résultat d’expression et tester si les valeurs résultantes correspondent à des modèles imbriqués.
- Modèle
var
: pour faire correspondre n’importe quelle expression et affecter son résultat à une variable déclarée. - Modèle Discard : pour faire correspondre n’importe quelle expression.
- Modèles de liste : pour tester qu’une séquence d’éléments correspond aux modèles imbriqués correspondants. Introduit dans C# 11.
Les modèles logiques, de propriété, positionnels et de liste sont des modèles récursifs. Autrement dit, ils peuvent contenir des modèles imbriqués.
Pour voir un exemple d’utilisation de ces modèles afin de créer un algorithme piloté par les données, consultez le Tutoriel : Utiliser des critères spéciaux pour générer des algorithmes pilotés par type et pilotés par des données.
Modèles de déclaration et de type
Utilisez des modèles de déclaration et de type pour vérifier si le type d’exécution d’une expression est compatible avec un type donné. Avec un modèle de déclaration, vous pouvez également déclarer une nouvelle variable locale. Lorsqu’un modèle de déclaration correspond à une expression, cette variable reçoit un résultat d’expression convertie, comme l’illustre l’exemple suivant :
object greeting = "Hello, World!";
if (greeting is string message)
{
Console.WriteLine(message.ToLower()); // output: hello, world!
}
Un modèle de déclaration avec le type T
correspond à une expression lorsqu’un résultat d’expression n’est pas null et que l’une des conditions suivantes est vraie :
Le type d’exécution d’un résultat d’expression est
T
.Le type d’exécution d’un résultat d’expression dérive du type
T
, implémente l’interfaceT
, ou une autre conversion de référence implicite enT
existe à partir de celui-ci. L’exemple suivant illustre deux cas où cette condition a la valeur true :var numbers = new int[] { 10, 20, 30 }; Console.WriteLine(GetSourceLabel(numbers)); // output: 1 var letters = new List<char> { 'a', 'b', 'c', 'd' }; Console.WriteLine(GetSourceLabel(letters)); // output: 2 static int GetSourceLabel<T>(IEnumerable<T> source) => source switch { Array array => 1, ICollection<T> collection => 2, _ => 3, };
Dans l’exemple précédent, au premier appel à la méthode
GetSourceLabel
, le premier modèle correspond à une valeur d’argument, car le type d’exécutionint[]
de l’argument dérive du type Array. Au deuxième appel à la méthodeGetSourceLabel
, le type d’exécution List<T> de l’argument ne dérive pas du type Array, mais implémente l’interface ICollection<T>.Le type d’exécution d’un résultat d’expression est un type de valeur pouvant accepter la valeur Null avec le type sous-jacent
T
.Il existe une conversion boxing ou unboxing en type
T
à partir du type d’exécution d’un résultat d’expression.
L’exemple suivant illustre les deux dernières conditions :
int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
Console.WriteLine(a + b); // output: 30
}
Si vous souhaitez vérifier uniquement le type d’une expression, vous pouvez utiliser un caractère _
de type Discard à la place du nom d’une variable, comme l’illustre l’exemple suivant :
public abstract class Vehicle {}
public class Car : Vehicle {}
public class Truck : Vehicle {}
public static class TollCalculator
{
public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
Car _ => 2.00m,
Truck _ => 7.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
}
À cet effet, vous pouvez utiliser un modèle de type, comme l’illustre l’exemple suivant :
public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
Car => 2.00m,
Truck => 7.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
À l’instar d’un modèle de déclaration, un modèle de type correspond à une expression lorsqu’un résultat d’expression est non null et que son type d’exécution satisfait à l’une des conditions précédentes.
Pour rechercher des valeurs non-null, vous pouvez utiliser un modèle de constante null
inversé, comme le montre l’exemple suivant :
if (input is not null)
{
// ...
}
Pour plus d’informations, consultez les sections Modèle de déclaration et Modèle de type des notes de proposition de fonctionnalités.
Modèle de constante
Vous utilisez un modèle de constante pour tester si un résultat d’expression est égal à une constante spécifiée, comme l’illustre l’exemple suivant :
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
1 => 12.0m,
2 => 20.0m,
3 => 27.0m,
4 => 32.0m,
0 => 0.0m,
_ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
Dans un modèle constant, vous pouvez utiliser n’importe quelle expression constante, par exemple :
- un littéral numérique entier ou à virgule flottante
- char
- littéral de chaîne.
- une valeur booléenne
true
oufalse
- valeur enum
- le nom d’un champ const déclaré ou local
null
L’expression doit être un type convertible en type constant, à une exception près : une expression dont le type est Span<char>
ou ReadOnlySpan<char>
peut être mise en correspondance avec des chaînes constantes en C# 11 et versions ultérieures.
Utilisez un modèle constant pour rechercher null
, comme l’illustre l’exemple suivant :
if (input is null)
{
return;
}
Le compilateur garantit qu’aucun opérateur d’égalité ==
surchargé par l’utilisateur n’est appelé lorsque l’expression x is null
est évaluée.
Vous pouvez utiliser un modèle de constante inversé null
pour rechercher des valeurs non-null, comme le montre l’exemple suivant :
if (input is not null)
{
// ...
}
Pour plus d’informations, consultez la section Modèle de constante de la note de proposition de fonctionnalités.
Modèles relationnels
Vous utilisez un modèle relationnel pour comparer un résultat d’expression à une constante, comme l’illustre l’exemple suivant :
Console.WriteLine(Classify(13)); // output: Too high
Console.WriteLine(Classify(double.NaN)); // output: Unknown
Console.WriteLine(Classify(2.4)); // output: Acceptable
static string Classify(double measurement) => measurement switch
{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};
Dans un modèle relationnel, vous pouvez utiliser l’un des opérateurs relationnels <
, >
, <=
ou >=
. La partie droite d’un modèle relationnel doit être une expression constante. L’expression constante peut être d’un type entier, à virgule flottante, char ou énumération.
Pour vérifier si un résultat d’expression se trouve dans une certaine plage, faites-le correspondre à un modèle and
conjonctif, comme l’illustre l’exemple suivant :
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 3, 14))); // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 7, 19))); // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 2, 17))); // output: winter
static string GetCalendarSeason(DateTime date) => date.Month switch
{
>= 3 and < 6 => "spring",
>= 6 and < 9 => "summer",
>= 9 and < 12 => "autumn",
12 or (>= 1 and < 3) => "winter",
_ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};
Si un résultat d’expression est null
ou ne parvient pas à se convertir en type de constante par une conversion nullable ou unboxing, un modèle relationnel ne correspond pas à une expression.
Pour plus d’informations, consultez la section Modèles relationnels de la note de proposition de fonctionnalités.
Modèles logiques
Vous utilisez les combinateurs de modèles not
, and
et or
pour créer les modèles logiques suivants :
Modèle de négation
not
qui correspond à une expression lorsque le modèle inversé ne correspond pas à l’expression. L’exemple suivant montre comment inverser un modèle de constantenull
pour vérifier si une expression est non-null :if (input is not null) { // ... }
Modèle conjonctif
and
qui correspond à une expression lorsque les deux modèles correspondent à l’expression. L’exemple suivant montre comment combiner des modèles relationnels pour vérifier si une valeur se trouve dans une certaine plage :Console.WriteLine(Classify(13)); // output: High Console.WriteLine(Classify(-100)); // output: Too low Console.WriteLine(Classify(5.7)); // output: Acceptable static string Classify(double measurement) => measurement switch { < -40.0 => "Too low", >= -40.0 and < 0 => "Low", >= 0 and < 10.0 => "Acceptable", >= 10.0 and < 20.0 => "High", >= 20.0 => "Too high", double.NaN => "Unknown", };
Modèle disjonctif
or
qui correspond à une expression lorsque l’un ou l’autre modèle correspond à l’expression, comme le montre l’exemple suivant :Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19))); // output: winter Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9))); // output: autumn Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11))); // output: spring static string GetCalendarSeason(DateTime date) => date.Month switch { 3 or 4 or 5 => "spring", 6 or 7 or 8 => "summer", 9 or 10 or 11 => "autumn", 12 or 1 or 2 => "winter", _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."), };
Comme l’illustre l’exemple précédent, vous pouvez utiliser à plusieurs reprises les combinateurs de modèles dans un modèle.
Priorité et ordre de vérification
Les combinateurs de modèle sont classés en fonction de l’ordre de liaison des expressions comme suit :
not
and
or
Le not
modèle se lie d’abord à son opérande. Le and
modèle se lie après toute not
liaison d’expression de modèle. Le or
modèle se lie après tous not
et and
les modèles sont liés à des opérandes. L’exemple suivant tente de faire correspondre tous les caractères qui ne sont pas des lettres minuscules. a
- z
Il a une erreur, car le not
modèle se lie avant le and
modèle :
// Incorrect pattern. `not` binds before `and`
static bool IsNotLowerCaseLetter(char c) => c is not >= 'a' and <= 'z';
La liaison par défaut signifie que l’exemple précédent est analysé comme l’exemple suivant :
// The default binding without parentheses is shows in this method. `not` binds before `and`
static bool IsNotLowerCaseLetterDefaultBinding(char c) => c is ((not >= 'a') and <= 'z');
Pour résoudre ce problème, vous devez spécifier que vous souhaitez que la not
liaison soit liée à l’expression >= 'a' and <= 'z'
:
// Correct pattern. Force `and` before `not`
static bool IsNotLowerCaseLetterParentheses(char c) => c is not (>= 'a' and <= 'z');
L’ajout de parenthèses devient plus important, car vos modèles deviennent plus compliqués. En général, utilisez des parenthèses pour clarifier vos modèles pour d’autres développeurs, comme l’illustre l’exemple suivant :
static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');
Remarque
L’ordre dans lequel les modèles ayant le même ordre de liaison sont vérifiés n’est pas défini. Au moment de l’exécution, les modèles imbriqués à droite de plusieurs or
modèles et plusieurs and
modèles peuvent être vérifiés en premier.
Pour plus d’informations, consultez la section Combinateurs de modèles de la note de proposition de fonctionnalités.
Modèle de propriété
Vous utilisez un modèle de propriété pour faire correspondre les propriétés ou les champs d’une expression aux modèles imbriqués, comme l’illustre l’exemple suivant :
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
Un modèle de propriété correspond à une expression lorsqu’un résultat d’expression est non-null et chaque modèle imbriqué correspond à la propriété ou au champ correspondant du résultat de l’expression.
Vous pouvez également ajouter une vérification de type d’exécution et une déclaration de variable à un modèle de propriété, comme l’illustre l’exemple suivant :
Console.WriteLine(TakeFive("Hello, world!")); // output: Hello
Console.WriteLine(TakeFive("Hi!")); // output: Hi!
Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' })); // output: 12345
Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' })); // output: abc
static string TakeFive(object input) => input switch
{
string { Length: >= 5 } s => s.Substring(0, 5),
string s => s,
ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
ICollection<char> symbols => new string(symbols.ToArray()),
null => throw new ArgumentNullException(nameof(input)),
_ => throw new ArgumentException("Not supported input type."),
};
Un modèle de propriété est un modèle récursif. Autrement dit, vous pouvez utiliser n’importe quel modèle comme modèle imbriqué. Utilisez un modèle de propriété pour faire correspondre des parties de données à des modèles imbriqués, comme l’illustre l’exemple suivant :
public record Point(int X, int Y);
public record Segment(Point Start, Point End);
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start: { Y: 0 } } or { End: { Y: 0 } };
L’exemple précédent utilise le combinateur de modèles or
et les types d’enregistrements.
À compter de C# 10, vous pouvez référencer des propriétés ou des champs imbriqués dans un modèle de propriété. Cette fonctionnalité est appelée modèle de propriété étendu. Par exemple, vous pouvez refactoriser la méthode de l’exemple précédent dans le code équivalent suivant :
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start.Y: 0 } or { End.Y: 0 };
Pour plus d’informations, consultez la section Modèle de propriété de la note de proposition de fonctionnalités et la note de proposition de fonctionnalités Modèles de propriétés étendus.
Conseil
Vous pouvez utiliser la règle de style Simplifier le modèle de propriété (IDE0170) pour améliorer la lisibilité du code en suggérant des emplacements pour utiliser des modèles de propriétés étendus.
Modèle positionnel
Vous utilisez un modèle positionnel pour déconstruire un résultat d’expression et faire correspondre les valeurs obtenues avec les modèles imbriqués correspondants, comme l’illustre l’exemple suivant :
public readonly struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}
static string Classify(Point point) => point switch
{
(0, 0) => "Origin",
(1, 0) => "positive X basis end",
(0, 1) => "positive Y basis end",
_ => "Just a point",
};
Dans l’exemple précédent, le type d’une expression contient la méthode Deconstruct, qui est utilisée pour déconstruire un résultat d’expression.
Important
L'ordre des membres d'un motif positionnel doit correspondre à l'ordre des paramètres de la méthode Deconstruct
. C'est parce que le code généré pour le motif positionnel appelle la méthode Deconstruct
.
Vous pouvez également faire correspondre des expressions de types de tuple avec des modèles positionnels. De cette façon, vous pouvez faire correspondre plusieurs entrées avec différents modèles, comme l’illustre l’exemple suivant :
static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)
=> (groupSize, visitDate.DayOfWeek) switch
{
(<= 0, _) => throw new ArgumentException("Group size must be positive."),
(_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,
(>= 5 and < 10, DayOfWeek.Monday) => 20.0m,
(>= 10, DayOfWeek.Monday) => 30.0m,
(>= 5 and < 10, _) => 12.0m,
(>= 10, _) => 15.0m,
_ => 0.0m,
};
L’exemple précédent utilise des modèles relationnels et logiques.
Vous pouvez utiliser les noms des éléments de tuple et les paramètres Deconstruct
dans un modèle positionnel, comme l’illustre l’exemple suivant :
var numbers = new List<int> { 1, 2, 3 };
if (SumAndCount(numbers) is (Sum: var sum, Count: > 0))
{
Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}"); // output: Sum of [1 2 3] is 6
}
static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers)
{
int sum = 0;
int count = 0;
foreach (int number in numbers)
{
sum += number;
count++;
}
return (sum, count);
}
Vous pouvez également étendre un modèle positionnel de l’une des manières suivantes :
Ajoutez une vérification de type d’exécution et une déclaration de variable, comme l’illustre l’exemple suivant :
public record Point2D(int X, int Y); public record Point3D(int X, int Y, int Z); static string PrintIfAllCoordinatesArePositive(object point) => point switch { Point2D (> 0, > 0) p => p.ToString(), Point3D (> 0, > 0, > 0) p => p.ToString(), _ => string.Empty, };
L’exemple précédent utilise des enregistrements positionnels qui fournissent implicitement la méthode
Deconstruct
.Utilisez un modèle de propriété dans un modèle positionnel, comme l’illustre l’exemple suivant :
public record WeightedPoint(int X, int Y) { public double Weight { get; set; } } static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };
Combinez deux utilisations précédentes, comme l’illustre l’exemple suivant :
if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p) { // .. }
Un modèle positionnel est un modèle récursif. Autrement dit, vous pouvez utiliser n’importe quel modèle comme modèle imbriqué.
Pour plus d’informations, consultez la section Modèle positionnel de la note de proposition de fonctionnalités.
var
motif
Vous utilisez un modèle var
pour faire correspondre n’importe quelle expression, y compris null
, et affecter son résultat à une nouvelle variable locale, comme l’illustre l’exemple suivant :
static bool IsAcceptable(int id, int absLimit) =>
SimulateDataFetch(id) is var results
&& results.Min() >= -absLimit
&& results.Max() <= absLimit;
static int[] SimulateDataFetch(int id)
{
var rand = new Random();
return Enumerable
.Range(start: 0, count: 5)
.Select(s => rand.Next(minValue: -10, maxValue: 11))
.ToArray();
}
Un modèle var
est utile lorsque vous avez besoin qu’une variable temporaire dans une expression booléenne contienne le résultat des calculs intermédiaires. Vous pouvez également utiliser un modèle var
lorsque vous devez effectuer davantage de vérifications dans les gardes de cas when
d’une expression ou d’une instruction switch
, comme l’illustre l’exemple suivant :
public record Point(int X, int Y);
static Point Transform(Point point) => point switch
{
var (x, y) when x < y => new Point(-x, y),
var (x, y) when x > y => new Point(x, -y),
var (x, y) => new Point(x, y),
};
static void TestTransform()
{
Console.WriteLine(Transform(new Point(1, 2))); // output: Point { X = -1, Y = 2 }
Console.WriteLine(Transform(new Point(5, 2))); // output: Point { X = 5, Y = -2 }
}
Dans l’exemple précédent, le modèle var (x, y)
équivaut à un modèle positionnel (var x, var y)
.
Dans un modèle var
, le type d’une variable déclarée est le type au moment de la compilation de l’expression qui est mis en correspondance avec le modèle.
Pour plus d’informations, consultez la section Modèle var de la note de proposition de fonctionnalités.
Ignorer le modèle
Vous utilisez un modèle discard _
pour faire correspondre n’importe quelle expression, y compris null
, comme le montre l’exemple suivant :
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)); // output: 5.0
Console.WriteLine(GetDiscountInPercent(null)); // output: 0.0
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10)); // output: 0.0
static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch
{
DayOfWeek.Monday => 0.5m,
DayOfWeek.Tuesday => 12.5m,
DayOfWeek.Wednesday => 7.5m,
DayOfWeek.Thursday => 12.5m,
DayOfWeek.Friday => 5.0m,
DayOfWeek.Saturday => 2.5m,
DayOfWeek.Sunday => 2.0m,
_ => 0.0m,
};
Dans l’exemple précédent, un modèle d’abandon est utilisé pour gérer null
et toute valeur entière qui n’a pas le membre correspondant de l’énumération DayOfWeek. Cela garantit qu’une expression switch
dans l’exemple gère toutes les valeurs d’entrée possibles. Si vous n’utilisez pas de modèle d’abandon dans une expression switch
et qu’aucun des modèles de l’expression ne correspond à une entrée, le runtime lève une exception. Le compilateur génère un avertissement si une expression switch
ne gère pas toutes les valeurs d’entrée possibles.
Un modèle d’abandon ne peut pas être un modèle dans une expression is
ou une instruction switch
. Dans ces cas, pour faire correspondre n’importe quelle expression, utilisez un modèle var
avec un caractère d’abandon : var _
. Un modèle d’abandon peut être un modèle dans une expression switch
.
Pour plus d’informations, consultez la section Modèle d’abandon de la note de proposition de fonctionnalités.
Modèle entre parenthèses
Vous pouvez placer des parenthèses autour de n’importe quel modèle. En règle générale, vous devez mettre en évidence ou modifier la priorité dans des modèles logiques, comme l’illustre l’exemple suivant :
if (input is not (float or double))
{
return;
}
Modèles de liste
À compter de C# 11, vous pouvez faire correspondre un tableau ou une liste à une séquence de modèles, comme l’illustre l’exemple suivant :
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
Console.WriteLine(numbers is [1, 2, 3, 4]); // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // True
Comme l’illustre l’exemple précédent, un modèle de liste est mis en correspondance lorsque chaque modèle imbriqué correspond à l’élément correspondant d’une séquence d’entrée. Vous pouvez utiliser n’importe quel modèle dans un modèle de liste. Pour faire correspondre n’importe quel élément, utilisez le modèle d’abandon ou, si vous souhaitez également capturer l’élément, le modèle var, comme l’illustre l’exemple suivant :
List<int> numbers = new() { 1, 2, 3 };
if (numbers is [var first, _, _])
{
Console.WriteLine($"The first element of a three-item list is {first}.");
}
// Output:
// The first element of a three-item list is 1.
Les exemples précédents correspondent à une séquence d’entrée entière par rapport à un modèle de liste. Pour faire correspondre des éléments uniquement au début ou/et à la fin d’une séquence d’entrée, utilisez le modèle de section ..
, comme le montre l’exemple suivant :
Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]); // True
Console.WriteLine(new[] { 1, 1 } is [_, _, ..]); // True
Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]); // False
Console.WriteLine(new[] { 1 } is [1, 2, ..]); // False
Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]); // True
Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]); // False
Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]); // True
Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]); // True
Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]); // True
Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]); // False
Un modèle de section correspond à zéro ou plusieurs éléments. Vous pouvez utiliser au plus un modèle de section dans un modèle de liste. Le modèle de section ne peut apparaître que dans un modèle de liste.
Vous pouvez également imbriquer un sous-modèle dans un modèle de section, comme l’illustre l’exemple suivant :
void MatchMessage(string message)
{
var result = message is ['a' or 'A', .. var s, 'a' or 'A']
? $"Message {message} matches; inner part is {s}."
: $"Message {message} doesn't match.";
Console.WriteLine(result);
}
MatchMessage("aBBA"); // output: Message aBBA matches; inner part is BB.
MatchMessage("apron"); // output: Message apron doesn't match.
void Validate(int[] numbers)
{
var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";
Console.WriteLine(result);
}
Validate(new[] { -1, 0, 1 }); // output: not valid
Validate(new[] { -1, 0, 0, 1 }); // output: valid
Pour plus d’informations, consultez la note de proposition de fonctionnalités Modèles de liste.
spécification du langage C#
Pour plus d’informations, consultez la section Modèles et correspondances de modèles de la spécification du langage C#.
Pour plus d’informations sur les fonctionnalités ajoutées en C# 8 et ultérieur, consultez la note de propositions de fonctionnalités :
- Critères spéciaux récursifs
- Mises à jour de correspondance de modèles
- C# 10 - Modèles de propriétés étendus
- C# 11 - Modèles de liste
- C# 11 - Correspondance de modèle
Span<char>
sur un littéral de chaîne