C# Pattern Matching Expressions (Comment ça fonctionne pour les développeurs)
La correspondance de motifs dans C# est une fonctionnalité puissante qui a été introduite dans C# 7.0 et qui a depuis été développée dans les versions suivantes. Il permet aux développeurs d'écrire un code plus concis et plus expressif lorsqu'ils utilisent des instructions conditionnelles, la vérification de type et la déconstruction d'objets.
Les expressions de correspondance de motifs offrent un moyen souple et intuitif de faire correspondre des valeurs à des motifs et d'exécuter les blocs de code correspondants. Dans cet article, nous allons explorer les subtilités des expressions de correspondance de motifs en C#, notamment la syntaxe, les cas d'utilisation et les exemples de code. À la fin de l'article, nous explorerons également un peu la bibliothèque de génération de PDF IronPDF de Iron Software pour générer un document PDF à la volée dans les applications C#.
Avantages de la correspondance de motifs en C
La recherche de motifs dans le code C# présente une pléthore d'avantages :
- Lisibilité améliorée : la correspondance de modèles simplifie la logique conditionnelle complexe, rendant votre code plus facile à comprendre et à suivre pour vous-même et pour les autres développeurs.
- Réduction du nombre de lignes de code : en condensant les instructions conditionnelles complexes en modèles concis, la correspondance de modèles contribue à rationaliser votre base de code, ce qui permet de réduire le nombre de lignes de code et d'obtenir une implémentation plus succincte.
- Maintenabilité améliorée : la clarté offerte par la correspondance de modèles facilite la maintenance et le débogage du code. Les modèles étant clairement définis, il devient plus simple d'identifier et de modifier des blocs logiques spécifiques en fonction des besoins, sans affecter le reste de la base de code.
- Des algorithmes plus expressifs : la correspondance de modèles permet aux développeurs d'exprimer les algorithmes de manière plus naturelle et intuitive. En alignant les structures de code sur les paradigmes de résolution de problèmes, le pattern matching facilite la création d'algorithmes qui ressemblent étroitement à leurs modèles conceptuels.
Types de correspondance de motifs en C
La recherche de motifs est prise en charge par les expressions suivantes :
isexpressionswitchdéclarationsswitchexpressions
Les modèles suivants peuvent être utilisés pour correspondre aux constructions :
Déclaration et modèles de type
Les modèles de déclaration et de type sont des outils essentiels en C# pour vérifier la compatibilité des types d'exécution d'expression avec des types donnés. Avec les modèles de déclaration, vous pouvez à la fois vérifier la compatibilité et déclarer une nouvelle variable locale. Considérez l'exemple suivant :
object greeting = "Iron Software is Awesome!";
if (greeting is string message)
{
Console.WriteLine(message.ToLower()); // output: iron software is awesome!
}
object greeting = "Iron Software is Awesome!";
if (greeting is string message)
{
Console.WriteLine(message.ToLower()); // output: iron software is awesome!
}
Dim greeting As Object = "Iron Software is Awesome!"
Dim tempVar As Boolean = TypeOf greeting Is String
Dim message As String = If(tempVar, DirectCast(greeting, String), Nothing)
If tempVar Then
Console.WriteLine(message.ToLower()) ' output: iron software is awesome!
End If
Ici, le modèle de déclaration garantit que si l'expression greeting correspond au type string, elle est affectée à la variable message, permettant des opérations ultérieures.
Lorsque l'une des conditions suivantes est remplie, le modèle de déclaration est valable :
- Le type d'exécution de l'expression est
T. - Le type d'exécution de l'expression dérive de
T, implémente l'interfaceT, ou peut être implicitement converti enT. - Le type d'exécution de l'expression est un type de valeur nullable avec le type sous-jacent
T. - Une conversion d'encapsulation ou de déencapsulation existe entre le type d'exécution de l'expression et le type
T.
Prenons l'exemple suivant, qui illustre les conditions susmentionnées :
int? nullableX = 8;
int y = 45;
object boxedy = y;
if (nullableX is int a && boxedy is int b)
{
Console.WriteLine(a + b); // output: 53
}
int? nullableX = 8;
int y = 45;
object boxedy = y;
if (nullableX is int a && boxedy is int b)
{
Console.WriteLine(a + b); // output: 53
}
Dim nullableX? As Integer = 8
Dim y As Integer = 45
Dim boxedy As Object = y
Dim tempVar As Boolean = TypeOf boxedy Is Integer
Dim b As Integer = If(tempVar, DirectCast(boxedy, Integer), Nothing)
Dim tempVar2 As Boolean = TypeOf nullableX Is Integer
Dim a As Integer = If(tempVar2, CInt(nullableX), Nothing)
If tempVar2 AndAlso tempVar Then
Console.WriteLine(a + b) ' output: 53
End If
Ici, nullableX correspond au modèle car il s'agit d'un type de valeur nullable avec le type sous-jacent int, et boxedy correspond car il peut être déballé en int.
Lorsque vous avez uniquement besoin de vérifier le type d'expression sans déclarer de nouvelle variable, vous pouvez utiliser la fonction discard _, comme illustré dans l'exemple ci-dessous :
public static decimal CalculateToll(Vehicle vehicle) => vehicle switch
{
Bus _ => 4.00m,
Motor _ => 8.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
public static decimal CalculateToll(Vehicle vehicle) => vehicle switch
{
Bus _ => 4.00m,
Motor _ => 8.50m,
null => throw new ArgumentNullException(nameof(vehicle)),
_ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'public static decimal CalculateToll(Vehicle vehicle) => vehicle switch
'{
' Bus _ => 4.00m,
' Motor _ => 8.50m,
' null => throw new ArgumentNullException(nameof(vehicle)),
' _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
'};
Dans cet extrait, le _ sert d'espace réservé pour tout type correspondant à Vehicle.
Les motifs de déclaration et de type garantissent que les expressions ne sont pas nulles avant la mise en correspondance des motifs. Vous pouvez vérifier la non-nullité à l'aide d'un modèle de constante nullité annulée, comme illustré ci-dessous :
if (inputVal is not null)
{
// ...
}
if (inputVal is not null)
{
// ...
}
If inputVal IsNot Nothing Then
' ...
End If
Cette négation garantit que inputVal n'est pas nul avant de procéder à d'autres opérations.
En exploitant les modèles de déclaration et de type dans votre code C#, vous pouvez améliorer la lisibilité, réduire les lignes de code et exprimer les algorithmes plus efficacement. Ces modèles constituent un moyen concis et expressif de gérer la logique basée sur les types et d'améliorer la maintenabilité de votre base de code.
Modèle constant
Les motifs constants permettent de vérifier si le résultat d'une expression correspond à une valeur constante spécifique. Considérez l'exemple suivant :
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
1 => 2.0m,
2 => 10.0m,
3 => 25.0m,
4 => 60.0m,
0 => 0.0m,
_ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
1 => 2.0m,
2 => 10.0m,
3 => 25.0m,
4 => 60.0m,
0 => 0.0m,
_ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
Dim tempVar As Decimal
Select Case visitorCount
Case 1
tempVar = 2.0D
Case 2
tempVar = 10.0D
Case 3
tempVar = 25.0D
Case 4
tempVar = 60.0D
Case 0
tempVar = 0.0D
Case Else
'INSTANT VB TODO TASK: Throw expressions are not converted by Instant VB:
'ORIGINAL LINE: tempVar = throw new ArgumentException(string.Format("Not supported number of visitors: {0}", visitorCount), nameof(visitorCount));
tempVar = throw New ArgumentException($"Not supported number of visitors: {visitorCount}", NameOf(visitorCount))
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'public static decimal GetGroupTicketPrice(int visitorCount)
'{
' Return tempVar;
'}
Ici, les modèles constants vérifient si visitorCount correspond à l'une des valeurs constantes spécifiées et renvoient les prix des billets correspondants.
Dans un modèle constant, vous pouvez utiliser différents types d'expressions constantes, telles que :
- Litres numériques entiers ou à virgule flottante.
- Personnages.
- Chaînes littérales.
- Valeurs booléennes (
trueoufalse). - Valeurs de la liste.
- Le nom d'un champ const ou local déclaré.
null.
Une expression de type Span<char> ou ReadOnlySpan<char> peut correspondre à des chaînes constantes.
Pour vérifier la présence de null, utilisez un modèle constant comme celui-ci :
if (inputVal is null)
{
return;
}
if (inputVal is null)
{
return;
}
If inputVal Is Nothing Then
Return
End If
Ici, le modèle garantit que inputVal est nul avant de procéder à d'autres opérations.
Vous pouvez également utiliser un modèle de constante null négativé pour vérifier les valeurs non nulles :
if (inputVal is not null)
{
// ...
}
if (inputVal is not null)
{
// ...
}
If inputVal IsNot Nothing Then
' ...
End If
Ce modèle vérifie que inputVal n'est pas nul, permettant ainsi d'effectuer les opérations suivantes en toute sécurité.
En incorporant des modèles de constantes dans votre code C#, vous pouvez gérer efficacement les scénarios dans lesquels des valeurs constantes spécifiques doivent être mises en correspondance, améliorant ainsi la clarté et la maintenabilité du code.
Modèles relationnels
Les modèles relationnels permettent de comparer les résultats d'une expression avec des constantes. Considérez l'exemple suivant :
Console.WriteLine(Classify(20)); // output: Too high
Console.WriteLine(Classify(double.NaN)); // output: Unknown
Console.WriteLine(Classify(4)); // output: Acceptable
static string Classify(double measurement) => measurement switch
{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};
Console.WriteLine(Classify(20)); // output: Too high
Console.WriteLine(Classify(double.NaN)); // output: Unknown
Console.WriteLine(Classify(4)); // output: Acceptable
static string Classify(double measurement) => measurement switch
{
< -4.0 => "Too low",
> 10.0 => "Too high",
double.NaN => "Unknown",
_ => "Acceptable",
};
Console.WriteLine(Classify(20)) ' output: Too high
Console.WriteLine(Classify(Double.NaN)) ' output: Unknown
Console.WriteLine(Classify(4)) ' output: Acceptable
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'static string Classify(double measurement) => measurement switch
'{
' < -4.0 => "Too low",
' > 10.0 => "Too high",
' double.NaN => "Unknown",
' _ => "Acceptable",
'};
Ici, les modèles relationnels comparent le measurement à des seuils spécifiques pour déterminer sa classification.
La partie droite d'un modèle relationnel doit être une expression constante, qui peut être de type entier, à virgule flottante, char ou enum. Les opérateurs <, >, <=, >= peuvent être utilisés à gauche.
Pour faire correspondre le résultat d'une expression à une plage donnée, utilisez un modèle conjonctif "et", comme illustré ci-dessous :
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 3, 12))); // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 7, 12))); // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 2, 12))); // 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}."),
};
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 3, 12))); // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 7, 12))); // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2024, 2, 12))); // 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}."),
};
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 3, 12))) ' output: spring
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 7, 12))) ' output: summer
Console.WriteLine(GetCalendarSeason(New DateTime(2024, 2, 12))) ' output: winter
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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}."),
'};
Cet extrait décrit comment la conjonction "et" est utilisée pour déterminer la saison calendaire en fonction du mois qui se situe dans une fourchette spécifique. Elle mentionne également que les modèles relationnels fournissent un moyen concis et expressif de comparer les résultats d'une expression à des constantes, améliorant ainsi la clarté et la maintenabilité du code.
Modèle de rejet
Le modèle de rejet, noté _, sert à correspondre à n'importe quelle expression, y compris null. Prenons 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,
};
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,
};
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)) ' output: 5.0
Console.WriteLine(GetDiscountInPercent(Nothing)) ' output: 0.0
Console.WriteLine(GetDiscountInPercent(CType(10, DayOfWeek))) ' output: 0.0
Dim tempVar As Decimal
Select Case dayOfWeek
Case DayOfWeek.Monday
tempVar = 0.5D
Case DayOfWeek.Tuesday
tempVar = 12.5D
Case DayOfWeek.Wednesday
tempVar = 7.5D
Case DayOfWeek.Thursday
tempVar = 12.5D
Case DayOfWeek.Friday
tempVar = 5.0D
Case DayOfWeek.Saturday
tempVar = 2.5D
Case DayOfWeek.Sunday
tempVar = 2.0D
Case Else
tempVar = 0.0D
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'static decimal GetDiscountInPercent(System.Nullable(Of DayOfWeek) dayOfWeek)
'{
' Return tempVar;
'}
Dans l'exemple du modèle de rejet ci-dessus, il traite toutes les valeurs d'entrée possibles. Tous les jours de la semaine sont gérés et une valeur par défaut est fournie. Ainsi, toutes les valeurs possibles sont prises en compte. Le modèle de rejet ne peut pas être utilisé comme modèle dans une expression is ou une instruction switch. Dans de tels cas, un modèle var peut être utilisé avec un rejet, comme var _, pour correspondre à n'importe quelle expression. Toutefois, un modèle de rejet est autorisé dans une expression switch. Pour plus de détails, veuillez vous référer à la section "Discard pattern" de la note de proposition de fonctionnalité.
Modèles logiques
Les motifs logiques en C# offrent des outils puissants pour la correspondance des motifs, notamment la négation, la conjonction et la disjonction, qui permettent des conditions de correspondance plus souples et plus expressives.
Négation (not modèle)
Le modèle de négation, représenté par not, correspond à une expression lorsque le modèle négatif ne correspond pas à l'expression. Ceci est particulièrement utile pour vérifier si une expression est non nulle, comme démontré ci-dessous :
if (input is not null)
{
// ...
}
if (input is not null)
{
// ...
}
If input IsNot Nothing Then
' ...
End If
Ici, le bloc de code est exécuté si input n'est pas nul.
Modèle conjonctif (and)
Le modèle conjonctif, utilisant le mot-clé and, correspond à une expression lorsque les deux modèles correspondent à l'expression. Cela permet de combiner plusieurs conditions, comme l'illustre l'exemple suivant :
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",
};
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",
};
Console.WriteLine(Classify(13)) ' output: High
Console.WriteLine(Classify(-100)) ' output: Too low
Console.WriteLine(Classify(5.7)) ' output: Acceptable
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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",
'};
Dans cet exemple, le measurement est classé en fonction de sa plage de valeurs.
Disjonctif (or modèle)
Le modèle disjonctif, utilisant le mot-clé or, correspond à une expression lorsque l'un ou l'autre modèle correspond à l'expression. Cela permet de traiter plusieurs conditions possibles, comme indiqué ci-dessous :
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}."),
};
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}."),
};
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
Dim tempVar As String
Select Case [date].Month
Case 3, 4, 5
tempVar = "spring"
Case 6, 7, 8
tempVar = "summer"
Case 9, 10, 11
tempVar = "autumn"
Case 12, 1, 2
tempVar = "winter"
Case Else
'INSTANT VB TODO TASK: Throw expressions are not converted by Instant VB:
'ORIGINAL LINE: tempVar = throw new ArgumentOutOfRangeException(nameof(date), string.Format("Date with unexpected month: {0}.", date.Month));
tempVar = throw New ArgumentOutOfRangeException(NameOf([date]), $"Date with unexpected month: {[date].Month}.")
End Select
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'static string GetCalendarSeason(DateTime @date)
'{
' Return tempVar;
'}
Ici, la saison calendaire est déterminée en fonction du mois de la date fournie.
Ces combinateurs de motifs peuvent être utilisés à plusieurs reprises pour créer des conditions de correspondance plus complexes et plus précises, améliorant ainsi la flexibilité et la lisibilité de votre code.
Modèle de propriété
Le motif de propriété permet de faire correspondre les propriétés ou les champs d'une expression à des motifs imbriqués. L'extrait de code suivant en est un exemple :
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };
Shared Function IsConferenceDay(ByVal [date] As DateTime) As Boolean
'INSTANT VB TODO TASK: The following 'is' operator pattern is not converted by Instant VB:
Return [date] is { Year: 2020, Month: 5, Day: 19 [or] 20 [or] 21 }
End Function
Ici, le modèle de propriété garantit que la date fournie correspond à l'un des jours de conférence spécifiés.
Vous pouvez également incorporer une vérification de type à l'exécution et une déclaration de variable dans un modèle de propriété, comme illustré ci-dessous :
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("Unsupported input type."),
};
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("Unsupported input type."),
};
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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("Unsupported input type."),
'};
Ici, le modèle de propriété est utilisé pour gérer les chaînes de caractères et les collections de caractères, en garantissant un traitement approprié en fonction de leurs propriétés.
Modèle positionnel
En C#, le motif positionnel permet de déconstruire le résultat d'une expression et de faire correspondre les valeurs obtenues à des motifs imbriqués correspondants. Par exemple:
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",
};
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",
};
'INSTANT VB WARNING: VB has no equivalent to the C# readonly struct:
'ORIGINAL LINE: public readonly struct Point
Public Structure Point
Public ReadOnly Property X() As Integer
Public ReadOnly Property Y() As Integer
Public Sub New(ByVal x As Integer, ByVal y As Integer)
'INSTANT VB TODO TASK: VB has no equivalent to the C# deconstruction assignments:
(X, Y) = (x, y)
End Sub
Public Sub Deconstruct(<System.Runtime.InteropServices.Out()> ByRef x As Integer, <System.Runtime.InteropServices.Out()> ByRef y As Integer)
'INSTANT VB TODO TASK: VB has no equivalent to the C# deconstruction assignments:
(x, y) = (X, Y)
End Sub
End Structure
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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 cet exemple, le modèle positionnel est utilisé pour classer les points en fonction de leurs coordonnées.
En outre, vous pouvez référencer des propriétés ou des champs imbriqués dans un modèle de propriété, connu sous le nom de modèle de propriété étendu, introduit dans C# 10 :
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start.Y: 0 } or { End.Y: 0 };
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start.Y: 0 } or { End.Y: 0 };
Shared Function IsAnyEndOnXAxis(ByVal segment As Segment) As Boolean
'INSTANT VB TODO TASK: The following 'is' operator pattern is not converted by Instant VB:
Return segment is { Start.Y: 0 } [or] { [End].Y: 0 }
End Function
Cette fonctionnalité améliore la flexibilité des modèles de propriété en permettant un accès direct aux propriétés imbriquées.
Ces modèles fournissent des mécanismes puissants pour gérer des structures de données complexes et améliorer la lisibilité et l'expressivité de votre code.
Modèle de variable
Var Pattern vous permet de faire correspondre n'importe quel type. Ces outils peuvent être particulièrement utiles pour capturer des résultats intermédiaires dans des expressions booléennes ou lorsque des vérifications multiples sont nécessaires dans des gardes de cas de commutation.
Voici un exemple démontrant l'utilisation du motif var dans une expression booléenne :
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();
}
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();
}
Shared Function IsAcceptable(ByVal id As Integer, ByVal absLimit As Integer) As Boolean
Dim tempVar As Boolean = TypeOf SimulateDataFetch(id) Is var
Dim results = If(tempVar, CType(SimulateDataFetch(id), var), Nothing)
Return tempVar AndAlso results.Min() >= -absLimit AndAlso results.Max() <= absLimit
End Function
Shared Function SimulateDataFetch(ByVal id As Integer) As Integer()
Dim rand = New Random()
Return Enumerable.Range(start:= 0, count:= 5).Select(Function(s) rand.Next(minValue:= -10, maxValue:= 11)).ToArray()
End Function
Dans cet exemple, SimulateDataFetch renvoie un tableau d'entiers, et le modèle is var capture le résultat dans la variable results, permettant des calculs ultérieurs basés sur ses propriétés.
En outre, les modèles var peuvent être utilisés dans les expressions ou les déclarations switch pour un code plus concis et plus lisible. Voici un exemple utilisant le motif var dans les gardes de cas de commutation :
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 }
}
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 }
}
'INSTANT VB TODO TASK: C# 'records' are not converted by Instant VB:
'public record Point(int X, int Y)
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'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),
'};
Shared Sub 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 }
End Sub
Dans cet exemple, le modèle var (x, y) capture les coordonnées du point, permettant différentes transformations en fonction de leurs valeurs.
Dans un motif var, le type de la variable déclarée est déduit du type à la compilation de l'expression correspondant au motif.
Le modèle var offre un moyen pratique de gérer divers scénarios dans lesquels le type spécifique d'expression n'est pas connu à l'avance, améliorant ainsi la clarté et la flexibilité du code.
Présentation de la bibliothèque IronPDF
IronPDF Document Rendering est une bibliothèque d'Iron Software spécialisée dans la génération de documents PDF. Pour commencer, la première chose à faire est d'installer la bibliothèque à partir du Package Manager NuGet ou du Package Manager Visual Studio.
# To install from the NuGet Package Manager Console
Install-Package IronPdf
# To install from the NuGet Package Manager Console
Install-Package IronPdf
L'image ci-dessous montre comment procéder à l'installation à partir du Guide d'installation de Visual Studio.

Dans le code ci-dessous, nous verrons comment générer un simple document PDF :
using IronPdf;
namespace IronPatterns
{
class Program
{
static void Main()
{
Console.WriteLine("-----------Iron Software-------------");
var renderer = new ChromePdfRenderer(); // var pattern
var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";
// Declaration Pattern
int? nullableX = 8;
int y = 45;
object boxedy = y;
content += "<p>Declaration Pattern</p>";
if (nullableX is int a && boxedy is int b)
{
Console.WriteLine(a + b); // output: 53
content += $"<p>Output: {(a + b)}</p>";
}
// Relational patterns
content += "<p>Relational patterns</p>";
var season1 = GetCalendarSeason(new DateTime(2024, 2, 25));
Console.WriteLine(season1);
content += $"<p>2024, 2, 25: {season1}</p>";
var season2 = GetCalendarSeason(new DateTime(2024, 5, 25));
Console.WriteLine(season2);
content += $"<p>2024, 5, 25: {season2}</p>";
var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
Console.WriteLine(season3);
content += $"<p>2024, 7, 25: {season3}</p>";
var pdf = renderer.RenderHtmlAsPdf(content);
pdf.SaveAs("output.pdf"); // Saves our PdfDocument object as a PDF
}
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}."),
};
}
}
using IronPdf;
namespace IronPatterns
{
class Program
{
static void Main()
{
Console.WriteLine("-----------Iron Software-------------");
var renderer = new ChromePdfRenderer(); // var pattern
var content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!";
// Declaration Pattern
int? nullableX = 8;
int y = 45;
object boxedy = y;
content += "<p>Declaration Pattern</p>";
if (nullableX is int a && boxedy is int b)
{
Console.WriteLine(a + b); // output: 53
content += $"<p>Output: {(a + b)}</p>";
}
// Relational patterns
content += "<p>Relational patterns</p>";
var season1 = GetCalendarSeason(new DateTime(2024, 2, 25));
Console.WriteLine(season1);
content += $"<p>2024, 2, 25: {season1}</p>";
var season2 = GetCalendarSeason(new DateTime(2024, 5, 25));
Console.WriteLine(season2);
content += $"<p>2024, 5, 25: {season2}</p>";
var season3 = GetCalendarSeason(new DateTime(2024, 7, 25));
Console.WriteLine(season3);
content += $"<p>2024, 7, 25: {season3}</p>";
var pdf = renderer.RenderHtmlAsPdf(content);
pdf.SaveAs("output.pdf"); // Saves our PdfDocument object as a PDF
}
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}."),
};
}
}
Imports IronPdf
Namespace IronPatterns
Friend Class Program
Shared Sub Main()
Console.WriteLine("-----------Iron Software-------------")
Dim renderer = New ChromePdfRenderer() ' var pattern
Dim content = " <h1> Iron Software is Awesome </h1> Made with IronPDF!"
' Declaration Pattern
Dim nullableX? As Integer = 8
Dim y As Integer = 45
Dim boxedy As Object = y
content &= "<p>Declaration Pattern</p>"
Dim tempVar As Boolean = TypeOf boxedy Is Integer
Dim b As Integer = If(tempVar, DirectCast(boxedy, Integer), Nothing)
Dim tempVar2 As Boolean = TypeOf nullableX Is Integer
Dim a As Integer = If(tempVar2, CInt(nullableX), Nothing)
If tempVar2 AndAlso tempVar Then
Console.WriteLine(a + b) ' output: 53
content &= $"<p>Output: {(a + b)}</p>"
End If
' Relational patterns
content &= "<p>Relational patterns</p>"
Dim season1 = GetCalendarSeason(New DateTime(2024, 2, 25))
Console.WriteLine(season1)
content &= $"<p>2024, 2, 25: {season1}</p>"
Dim season2 = GetCalendarSeason(New DateTime(2024, 5, 25))
Console.WriteLine(season2)
content &= $"<p>2024, 5, 25: {season2}</p>"
Dim season3 = GetCalendarSeason(New DateTime(2024, 7, 25))
Console.WriteLine(season3)
content &= $"<p>2024, 7, 25: {season3}</p>"
Dim pdf = renderer.RenderHtmlAsPdf(content)
pdf.SaveAs("output.pdf") ' Saves our PdfDocument object as a PDF
End Sub
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
' 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}."),
' };
End Class
End Namespace
Sortie

Détails du code
Ici, nous utilisons la classe ChromePdfRenderer d'IronPDF pour enregistrer la chaîne HTML dans un document PDF. Le résultat est enregistré dans le document "output.pdf".
Licence d'essai
IronPDF peut être utilisé avec une licence d'essai obtenue à partir de la page de licence IronPDF. Fournissez une adresse électronique pour générer une clé de licence qui vous sera envoyée par courrier électronique.
"IronPdf.LicenseKey": "<Your Key>"
"IronPdf.LicenseKey": "<Your Key>"
"IronPdf.LicenseKey" = "<Your Key>"
Placez la clé de licence dans le fichier appsettings.json comme indiqué ci-dessus.
Conclusion
Les expressions de correspondance de motifs en C# offrent un moyen puissant et flexible d'écrire des instructions conditionnelles, des vérifications de type et des déconstructions d'objets de manière concise et lisible. En tirant parti de la correspondance des modèles, les développeurs peuvent améliorer la clarté et la maintenabilité de leur code tout en réduisant la redondance et les formules passe-partout. Qu'il s'agisse de vérification de type, d'instructions de commutation ou de déconstruction, les expressions de correspondance de motifs constituent un ensemble d'outils polyvalents permettant de s'attaquer à un large éventail de tâches de programmation en C#.
En conclusion, la maîtrise des expressions de correspondance de motifs peut grandement améliorer vos compétences en programmation C#, vous permettant d'écrire un code plus propre et plus expressif, plus facile à comprendre et à maintenir. Nous avons également abordé les capacités de génération HTML vers PDF d'IronPDF, qui peuvent être exploitées pour générer des documents PDF.
Questions Fréquemment Posées
Comment puis-je utiliser la correspondance de motif pour améliorer la lisibilité du code en C# ?
La correspondance de motifs en C# permet aux développeurs d'écrire un code plus concis et expressif, rendant les instructions conditionnelles plus claires et plus faciles à comprendre. Cela améliore la lisibilité et la maintenabilité en réduisant la complexité des blocs de code.
Quels sont les différents types d'expressions de correspondance de modèle disponibles en C# ?
C# prend en charge diverses expressions de correspondance de modèle, y compris les expressions is, les instructions switch, et les expressions switch. Chaque type offre différentes manières d'évaluer les expressions et d'exécuter du code en fonction des motifs correspondants.
Comment puis-je générer des documents PDF à l'aide de C# ?
Vous pouvez utiliser IronPDF, une bibliothèque d'Iron Software, pour générer des documents PDF en C#. Il permet la conversion de contenu HTML en PDF et s'installe facilement via NuGet, offrant une large gamme de fonctionnalités de génération de PDF.
Quelles sont les annonces et les motifs de type dans la correspondance de motif C# ?
Les motifs de déclaration et de type en C# vérifient si le type d'exécution d'une expression correspond à un type spécifié et permettent la déclaration d'une nouvelle variable locale lorsqu'une correspondance est réussie, facilitant ainsi les opérations sécurisées par type.
Comment fonctionnent les motifs constants en C# ?
Les motifs constants en C# sont utilisés pour vérifier si une expression est égale à une valeur constante spécifique, telle qu'un entier ou une chaîne, et exécutent une certaine logique si une correspondance est trouvée, permettant des comparaisons de valeurs constantes simples.
Quel est le but des motifs relationnels en C# ?
Les motifs relationnels en C# permettent de comparer les expressions avec des constantes à l'aide d'opérateurs relationnels tels que <, >, <=, et >=. Ceci est utile pour implémenter des vérifications de plage concises dans votre code.
Comment les motifs logiques peuvent-ils être appliqués en C# ?
Les motifs logiques en C# combinent d'autres motifs à l'aide d'opérateurs logiques, tels que et, ou, et non, permettant des conditions de correspondance de motifs complexes pouvant évaluer plusieurs critères simultanément.
Qu'est-ce que le motif de rejet en C# et quand est-il utilisé ?
Le motif de rejet en C#, représenté par _, correspond à toute expression, y compris null, et est couramment utilisé dans les situations où des valeurs spécifiques doivent être ignorées, comme dans les expressions switch.
Comment les motifs de propriété peuvent-ils être utilisés en C# ?
Les motifs de propriété en C# permettent aux développeurs de faire correspondre les propriétés ou champs d'un objet avec des motifs imbriqués, fournissant un moyen d'effectuer des vérifications approfondies de la structure d'un objet tout en maintenant un code clair et concis.




