Modèles (référence C#)

C# a introduit la correspondance de modèle dans C# 7.0. Depuis lors, chaque version principale de C# étend les fonctionnalités de correspondance de modèles. Les expressions et instructions C# suivantes prennent en charge la correspondance des modèles :

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, affectez un résultat d’expression à une variable déclarée. Introduit dans C# 7.0.
  • Modèle de type : pour vérifier le type d’exécution d’une expression. Introduit dans C# 9.0.
  • Modèle constant : pour tester si un résultat d’expression est égal à une constante spécifiée. Introduit dans C# 7.0.
  • Modèles relationnels : pour comparer un résultat d’expression avec une constante spécifiée. Introduit dans C# 9.0.
  • Modèles logiques : pour tester si une expression correspond à une combinaison logique de modèles. Introduit dans C# 9.0.
  • Modèle de propriété : pour tester si les propriétés ou les champs d’une expression correspondent à des modèles imbriqués. Introduit dans C# 8.0.
  • Modèle positionnel : pour déconstructer un résultat d’expression et tester si les valeurs résultantes correspondent aux modèles imbriqués. Introduit dans C# 8.0.
  • var modèle : pour faire correspondre n’importe quelle expression et affecter son résultat à une variable déclarée. Introduit dans C# 7.0.
  • Ignorer le modèle : pour correspondre à n’importe quelle expression. Introduit dans C# 8.0.

Les modèles logiques, de propriété et positionnels sont des modèles récursifs . Autrement dit, ils peuvent contenir des modèles imbriqués .

Pour obtenir l’exemple d’utilisation de ces modèles pour créer un algorithme piloté par les données, consultez Tutoriel : Utiliser des modèles correspondants pour générer des algorithmes pilotés par type et pilotés par les données.

Modèles de déclaration et de type

Vous 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 est affectée à 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!
}

À compter de C# 7.0, un modèle de déclaration avec 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’interface T, ou une autre conversion de référence implicite existe de celui-ci vers T. L’exemple suivant illustre deux cas lorsque cette condition est vraie :

    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 GetSourceLabel méthode, le premier modèle correspond à une valeur d’argument, car le type int[] d’exécution de l’argument Array dérive du type. Au deuxième appel à la GetSourceLabel méthode, le type List<T> d’exécution de l’argument ne dérive pas du Array type, mais implémente l’interface ICollection<T> .

  • Le type d’exécution d’un résultat d’expression est un type valeur nullable avec le type Tsous-jacent .

  • Une conversion de boxe ou d’annulation existe du type d’exécution d’un résultat d’expression au type T.

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 abandon _ à 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)),
    };
}

À compter de C# 9.0, à 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)),
};

Comme un modèle de déclaration, un modèle de type correspond à une expression lorsqu’un résultat d’expression n’est pas null et que son type d’exécution satisfait à l’une des conditions répertoriées ci-dessus.

Vous pouvez également utiliser ce modèle pour une vérification claire et concise null :

if (input is not null)
{
    Console.WriteLine(input);
} else
{
    throw new ArgumentNullException(paramName: nameof(input), message: "Input should not be null");
}

Pour plus d’informations, consultez les sections modèles de déclaration et modèles de type des notes de proposition de fonctionnalités.

Modèle de constante

À compter de C# 7.0, vous utilisez un modèle constant 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 :

L’expression doit être un type convertible en type constant, à une exception près : expression dont le type est Span<char> ou ReadOnlySpan<char> peut être mis 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.

À compter de C# 9.0, vous pouvez utiliser un modèle de constante non-nullnull pour rechercher des valeurs non null, comme l’illustre l’exemple suivant :

if (input is not null)
{
    // ...
}

Pour plus d’informations, consultez la section Modèle constant de la note de proposition de fonctionnalité.

Modèles relationnels

À compter de C# 9.0, vous utilisez un modèle relationnel pour comparer un résultat d’expression avec 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 n’importe quel opérateur <relationnel, >, <=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, correspondez-le à un modèle conjonctifand, 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é.

Modèles logiques

À compter de C# 9.0, vous utilisez les notandcombinaisons de modèles et or de modèles pour créer les modèles logiques suivants :

  • Négationnot modèle qui correspond à une expression lorsque le modèle ne correspond pas à l’expression. L’exemple suivant montre comment annuler un modèle constantnull pour vérifier si une expression n’est pas null :

    if (input is not null)
    {
        // ...
    }
    
  • Conjonctifand modèle 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",
    };
    
  • Disjonctifor modèle qui correspond à une expression lorsque l’un des modèles correspond à l’expression, comme l’illustre 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 combinaisons de modèles dans un modèle.

Priorité et ordre de vérification

Les combinaisons de modèles de liste suivantes commencent par la priorité la plus élevée vers la plus basse :

  • not
  • and
  • or

Pour spécifier explicitement la priorité, utilisez des parenthèses, comme l’illustre l’exemple suivant :

static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');

Notes

L’ordre dans lequel les modèles sont vérifiés n’est pas défini. Au moment de l’exécution, les modèles imbriqués à droite des or modèles et and des modèles peuvent d’abord être vérifiés.

Pour plus d’informations, consultez la section Combinaisons de modèles de la note de proposition de fonctionnalité.

Modèle de propriété

À compter de C# 8.0, vous utilisez un modèle de propriété pour correspondre aux propriétés ou champs d’une expression par rapport 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 n’est pas null et que 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 deux fonctionnalités disponibles en C# 9.0 et versions ultérieures : orcombinaison de modèles et types d’enregistrements.

À compter de C# 10, vous pouvez référencer des propriétés ou des champs imbriqués au sein d’un modèle de propriété. Il s’agit d’un modèle de propriété étendu. Par exemple, vous pouvez refactoriser la méthode à partir 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é et la note de proposition de caractéristique des 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 endroits pour utiliser des modèles de propriétés étendus.

Modèle positionnel

À compter de C# 8.0, vous utilisez un modèle positionnel pour déconstructer un résultat d’expression et faire correspondre les valeurs résultantes aux modèles imbriqués correspondants, comme le montre 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éconstructer un résultat d’expression. Vous pouvez également faire correspondre des expressions de types tuples par rapport aux modèles positionnels. De cette façon, vous pouvez faire correspondre plusieurs entrées à 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 , qui sont disponibles dans C# 9.0 et versions ultérieures.

Vous pouvez utiliser les noms des éléments et Deconstruct des paramètres de tuple 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 Deconstruct méthode.

  • 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é.

var modèle

À compter de C# 7.0, vous utilisez un var modèle 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 var modèle est utile lorsque vous avez besoin d’une variable temporaire dans une expression booléenne pour contenir le résultat des calculs intermédiaires. Vous pouvez également utiliser un var modèle lorsque vous devez effectuer des vérifications supplémentaires dans les when gardes de cas d’une expression ou d’une switch instruction, 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 (var x, var y)positionnel.

Dans un var modèle, le type d’une variable déclarée est le type de compilation de l’expression qui correspond au modèle.

Pour plus d’informations, consultez la section Modèle Var de la note de proposition de fonctionnalité.

Ignorer le modèle

À compter de C# 8.0, vous utilisez un modèle _d’abandon pour faire correspondre n’importe quelle expression, y comprisnull, comme l’illustre 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 switch expression dans l’exemple gère toutes les valeurs d’entrée possibles. Si vous n’utilisez pas de modèle d’abandon dans une switch expression 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 switch expression 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 is expression ou une switch instruction. Dans ces cas, pour correspondre à n’importe quelle expression, utilisez un modèle avec un var abandon : var _.

Pour plus d’informations, consultez la section Ignorer le modèle de la note de proposition de fonctionnalité.

Modèle entre parenthèses

À compter de C# 9.0, 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 les 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 qui correspondent à des éléments. Vous pouvez appliquer l’un des modèles suivants :

  • Tout modèle peut être appliqué à n’importe quel élément pour vérifier qu’un élément individuel correspond à certaines caractéristiques.
  • Le modèle d’abandon (_) correspond à un seul élément.
  • Le modèle de plage (..) peut correspondre à zéro ou plusieurs éléments dans la séquence. Au plus un modèle de plage est autorisé dans un modèle de liste.
  • Le var modèle peut capturer un élément unique ou une plage d’éléments.

Ces règles sont illustrées à l’aide des déclarations de tableau suivantes :

int[] one = { 1 };
int[] odd = { 1, 3, 5 };
int[] even = { 2, 4, 6 };
int[] fib = { 1, 1, 2, 3, 5 };

Vous pouvez faire correspondre l’intégralité de la séquence en spécifiant tous les éléments et en utilisant des valeurs :

Console.WriteLine(odd is [1, 3, 5]); // true
Console.WriteLine(even is [1, 3, 5]); // false (values)
Console.WriteLine(one is [1, 3, 5]); // false (length)

Vous pouvez faire correspondre certains éléments dans une séquence d’une longueur connue à l’aide du modèle d’abandon (_) comme espace réservé :

Console.WriteLine(odd is [1, _, _]); // true
Console.WriteLine(odd is [_, 3, _]); // true
Console.WriteLine(even is [_, _, 5]); // false (last value)

Vous pouvez fournir n’importe quel nombre de valeurs ou d’espaces réservés n’importe où dans la séquence. Si vous n’êtes pas concerné par la longueur, vous pouvez utiliser le modèle de plage pour faire correspondre zéro ou plusieurs éléments :

Console.WriteLine(odd is [1, .., 3, _]); // true
Console.WriteLine(fib is [1, .., 3, _]); // true

Console.WriteLine(odd is [1, _, 5, ..]); // true
Console.WriteLine(fib is [1, _, 5, ..]); // false

Les exemples précédents utilisaient le modèle constant pour déterminer si un élément est un nombre donné. L’un de ces modèles peut être remplacé par un modèle différent, tel qu’un modèle relationnel :

Console.WriteLine(odd is [_, >1, ..]); // true
Console.WriteLine(even is [_, >1, ..]); // true
Console.WriteLine(fib is [_, > 1, ..]); // false

Les modèles de liste sont un outil précieux lorsque les données ne suivent pas une structure régulière. Vous pouvez utiliser des critères spéciaux pour tester la forme et les valeurs des données au lieu de les transformer en un ensemble d’objets.

Prenons l’extrait suivant d’un fichier texte contenant des transactions bancaires :

04-01-2020, DEPOSIT,    Initial deposit,            2250.00
04-15-2020, DEPOSIT,    Refund,                      125.65
04-18-2020, DEPOSIT,    Paycheck,                    825.65
04-22-2020, WITHDRAWAL, Debit,           Groceries,  255.73
05-01-2020, WITHDRAWAL, #1102,           Rent, apt, 2100.00
05-02-2020, INTEREST,                                  0.65
05-07-2020, WITHDRAWAL, Debit,           Movies,      12.57
04-15-2020, FEE,                                       5.55

Il s’agit d’un format CSV, mais certaines lignes ont plus de colonnes que d’autres. Pire encore pour le traitement, une colonne du type a du texte généré par l’utilisateur WITHDRAWAL et peut contenir une virgule dans le texte. Modèle de liste qui inclut le modèle d’abandon , le modèle constant et le modèle var pour capturer les données de traitement des données dans ce format :

decimal balance = 0m;
foreach (var transaction in ReadRecords())
{
    balance += transaction switch
    {
        [_, "DEPOSIT", _, var amount]     => decimal.Parse(amount),
        [_, "WITHDRAWAL", .., var amount] => -decimal.Parse(amount),
        [_, "INTEREST", var amount]       => decimal.Parse(amount),
        [_, "FEE", var fee]               => -decimal.Parse(fee),
        _                                 => throw new InvalidOperationException($"Record {transaction} is not in the expected format!"),
    };
    Console.WriteLine($"Record: {transaction}, New balance: {balance:C}");
}

L’exemple précédent prend un tableau de chaînes, où chaque élément est un champ dans la ligne. Clés d’expression de commutateur sur le deuxième champ, qui détermine le type de transaction et le nombre de colonnes restantes. Chaque ligne garantit que les données sont au format correct. Le modèle d’abandon (_) ignore le premier champ, avec la date de la transaction. Le deuxième champ correspond au type de transaction. L’élément restant correspond à ignorer le champ avec le montant. La correspondance finale utilise le modèle var pour capturer la représentation sous forme de chaîne de la quantité. L’expression calcule le montant à ajouter ou à soustraire du solde.

Les modèles de liste vous permettent de faire correspondre la forme d’une séquence d’éléments de données. Vous utilisez les modèles d’abandon et de plage pour correspondre à l’emplacement des éléments. Vous utilisez d’autres modèles pour faire correspondre les caractéristiques des éléments individuels.

spécification du langage C#

Pour plus d’informations, consultez les notes de proposition de fonctionnalités suivantes :

Voir aussi