Expressões de correspondência de padrões em C# (Como funciona para desenvolvedores)
A correspondência de padrões em C# é um recurso poderoso que foi introduzido no C# 7.0 e, desde então, expandido em versões subsequentes. Isso permite que os desenvolvedores escrevam um código mais conciso e expressivo ao lidar com instruções condicionais, verificação de tipos e desconstrução de objetos.
Expressões de correspondência de padrões oferecem uma maneira flexível e intuitiva de comparar valores com padrões e executar os blocos de código correspondentes. Neste artigo, exploraremos as complexidades das expressões de correspondência de padrões em C#, incluindo sintaxe, casos de uso e exemplos de código. Ao final do artigo, também exploraremos um pouco sobre a biblioteca IronPDF da Iron Software , que permite gerar documentos PDF dinamicamente em aplicações C#.
Benefícios do Casamento de Padrões em C
A correspondência de padrões em código C# apresenta uma série de vantagens:
- Legibilidade aprimorada: o casamento de padrões simplifica a lógica condicional complexa, tornando seu código mais fácil de entender e seguir, tanto para você quanto para outros desenvolvedores.
- Redução no número de linhas de código: Ao condensar instruções condicionais complexas em padrões concisos, o pattern matching ajuda a simplificar sua base de código, resultando em menos linhas de código e uma implementação mais sucinta.
- Melhoria na manutenção: A clareza proporcionada pela correspondência de padrões facilita a manutenção e a depuração do código. Com os padrões claramente definidos, torna-se mais simples identificar e modificar blocos lógicos específicos conforme necessário, sem afetar o restante do código.
- Algoritmos mais expressivos: O casamento de padrões permite que os desenvolvedores expressem algoritmos de uma maneira mais natural e intuitiva. Ao alinhar as estruturas de código com os paradigmas de resolução de problemas, o casamento de padrões facilita a criação de algoritmos que se assemelham bastante aos seus modelos conceituais.
Tipos de Casamento de Padrões em C
A correspondência de padrões é suportada pelas seguintes expressões:
isexpressãoswitchdeclaraçõesswitchexpressões
Os seguintes padrões podem ser usados para correspondência com as construções:
Padrões de Declaração e Tipo
Em C#, os padrões de declaração e de tipo são ferramentas essenciais para verificar a compatibilidade dos tipos de tempo de execução das expressões com os tipos especificados. Com os padrões de declaração, você pode verificar a compatibilidade e declarar uma nova variável local simultaneamente. Considere o seguinte exemplo:
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
Aqui, o padrão de declaração garante que, se a expressão greeting corresponder ao tipo string, ela será atribuída à variável message, possibilitando operações subsequentes.
O padrão Declaration é válido quando qualquer uma das seguintes condições for verdadeira:
- O tipo de tempo de execução da expressão é
T. - O tipo de tempo de execução da expressão deriva de
T, implementa a interfaceTou pode ser convertido implicitamente paraT. - O tipo de tempo de execução da expressão é um tipo de valor anulável com o tipo subjacente
T. - Existe uma conversão de boxing ou unboxing do tipo de tempo de execução da expressão para o tipo
T.
Considere o seguinte exemplo que demonstra as condições acima:
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
Aqui, nullableX corresponde ao padrão porque é um tipo de valor anulável com o tipo subjacente int, e boxedy corresponde porque pode ser desempacotado para int.
Quando você precisa apenas verificar o tipo de expressão sem declarar uma nova variável, pode utilizar o operador de descarte _, como mostrado no exemplo abaixo:
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)),
'};
Neste trecho, _ serve como um marcador para qualquer tipo que corresponda a Vehicle.
Tanto a declaração quanto os padrões de tipo garantem que as expressões não sejam nulas antes da correspondência de padrões. Você pode verificar se um valor não é nulo usando um padrão de constante nula negada, conforme ilustrado abaixo:
if (inputVal is not null)
{
// ...
}
if (inputVal is not null)
{
// ...
}
If inputVal IsNot Nothing Then
' ...
End If
Essa negação garante que inputVal não seja nulo antes de prosseguir com as operações subsequentes.
Ao aproveitar os padrões de declaração e tipagem em seu código C#, você pode melhorar a legibilidade, reduzir o número de linhas de código e expressar algoritmos de forma mais eficaz. Esses padrões fornecem uma maneira concisa e expressiva de lidar com a lógica baseada em tipos e melhoram a capacidade de manutenção do seu código.
Padrão constante
Padrões constantes servem para verificar se o resultado de uma expressão corresponde a um valor constante específico. Considere o seguinte exemplo:
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;
'}
Aqui, os padrões constantes verificam se visitorCount corresponde a algum dos valores constantes especificados e retornam os preços dos ingressos correspondentes.
Em um padrão constante, você pode empregar vários tipos de expressões constantes, tais como:
- Literais numéricos inteiros ou de ponto flutuante.
- Personagens.
- Literais de cadeia.
- Valores booleanos (
trueoufalse). - Valores de enumeração.
- O nome de um campo constante ou variável local declarada.
null.
Uma expressão do tipo Span<char> ou ReadOnlySpan<char> pode corresponder a cadeias de caracteres constantes.
Para verificar a ocorrência de null, utilize um padrão constante como este:
if (inputVal is null)
{
return;
}
if (inputVal is null)
{
return;
}
If inputVal Is Nothing Then
Return
End If
Aqui, o padrão garante que inputVal seja nulo antes de prosseguir com as operações subsequentes.
Você também pode usar um padrão de constante nula negada para determinar valores não nulos:
if (inputVal is not null)
{
// ...
}
if (inputVal is not null)
{
// ...
}
If inputVal IsNot Nothing Then
' ...
End If
Este padrão verifica se inputVal não é nulo, permitindo que as operações subsequentes sejam realizadas com segurança.
Ao incorporar padrões constantes em seu código C#, você pode lidar eficazmente com cenários em que valores constantes específicos precisam ser correspondidos, melhorando a clareza e a manutenção do código.
Padrões Relacionais
Os padrões relacionais fornecem um meio de comparar os resultados das expressões com constantes. Considere o seguinte exemplo:
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",
'};
Aqui, os padrões relacionais comparam o measurement com limites específicos para determinar sua classificação.
A parte direita de um padrão relacional deve ser uma expressão constante, que pode ser do tipo inteiro, de ponto flutuante, char ou enum. Os operadores <, >, <=, >= podem ser usados no lado esquerdo.
Para comparar o resultado de uma expressão dentro de um determinado intervalo, utilize a conjunção "e", conforme ilustrado abaixo:
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}."),
'};
Este excerto descreve como a conjunção "e" é utilizada para determinar a estação do ano no calendário, com base no mês que se enquadra em intervalos específicos. O texto também menciona que os padrões relacionais fornecem um meio conciso e expressivo de comparar os resultados das expressões com constantes, melhorando assim a clareza e a facilidade de manutenção do código.
Padrão de descarte
O padrão de descarte, denotado por _, serve para corresponder a qualquer expressão, incluindo null. Considere o seguinte exemplo:
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;
'}
No exemplo de padrão de descarte acima, ele lida com todos os valores de entrada possíveis. Todos os dias da semana são gerenciados e um valor padrão é fornecido. Dessa forma, todos os valores possíveis são tratados. O padrão de descarte não pode ser utilizado como um padrão em uma expressão is ou em uma instrução switch. Nesses casos, um padrão var pode ser usado com um descarte, como var _, para corresponder a qualquer expressão. No entanto, um padrão de descarte é permitido em uma expressão switch. Para obter mais detalhes, consulte a seção Padrão de descarte da nota de proposta de recurso.
Padrões Lógicos
Em C#, os padrões lógicos oferecem ferramentas poderosas para correspondência de padrões, incluindo negação, conjunção e disjunção, que permitem condições de correspondência mais flexíveis e expressivas.
Negação (not padrão)
O padrão de negação, representado por not, corresponde a uma expressão quando o padrão negado não corresponde à expressão. Isso é particularmente útil para verificar se uma expressão não é nula, como demonstrado abaixo:
if (input is not null)
{
// ...
}
if (input is not null)
{
// ...
}
If input IsNot Nothing Then
' ...
End If
Aqui, o bloco de código é executado se input não for nulo.
Padrão conjuntivo (and)
O padrão conjuntivo, usando a palavra-chave and, corresponde a uma expressão quando ambos os padrões correspondem à expressão. Isso permite combinar múltiplas condições, como ilustrado no exemplo a seguir:
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",
'};
Neste exemplo, o measurement é classificado com base em seu intervalo de valores.
Padrão disjuntivo (or)
O padrão disjuntivo, usando a palavra-chave or, corresponde a uma expressão quando qualquer um dos padrões corresponde à expressão. Isso permite lidar com múltiplas condições possíveis, conforme mostrado abaixo:
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;
'}
Aqui, a estação do ano no calendário é determinada com base no mês da data fornecida.
Esses combinadores de padrões podem ser usados repetidamente para criar condições de correspondência mais complexas e precisas, aumentando a flexibilidade e a legibilidade do seu código.
Padrão de propriedade
O padrão de propriedade permite a correspondência das propriedades ou campos de uma expressão com padrões aninhados. Um exemplo disso pode ser visto no seguinte trecho de código:
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
Neste caso, o padrão da propriedade garante que a data fornecida corresponda a um dos dias de conferência especificados.
Você também pode incorporar uma verificação de tipo em tempo de execução e uma declaração de variável dentro de um padrão de propriedade, como mostrado abaixo:
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."),
'};
Aqui, o padrão de propriedade é usado para lidar com strings e coleções de caracteres, garantindo o tratamento adequado com base em suas propriedades.
Padrão Posicional
Em C#, o padrão posicional permite desconstruir o resultado de uma expressão e comparar os valores resultantes com os padrões aninhados correspondentes. Por exemplo:
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",
'};
Neste exemplo, o padrão posicional é utilizado para classificar pontos com base em suas coordenadas.
Além disso, você pode referenciar propriedades ou campos aninhados dentro de um padrão de propriedade, conhecido como padrão de propriedade estendido, introduzido no 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
Essa funcionalidade aumenta a flexibilidade dos padrões de propriedades, permitindo o acesso direto a propriedades aninhadas.
Esses padrões fornecem mecanismos poderosos para lidar com estruturas de dados complexas e melhorar a legibilidade e a expressividade do seu código.
Padrão de Var
O padrão Var permite que você encontre correspondências para qualquer tipo. Isso pode ser particularmente útil para capturar resultados intermediários em expressões booleanas ou quando várias verificações são necessárias em estruturas de verificação switch case.
Aqui está um exemplo que demonstra o uso do padrão var em uma expressão booleana:
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
Neste exemplo, SimulateDataFetch retorna uma matriz de inteiros, e o padrão is var captura o resultado na variável results, permitindo cálculos subsequentes com base em suas propriedades.
Além disso, os padrões de variáveis podem ser utilizados em expressões ou instruções switch para um código mais conciso e legível. Aqui está um exemplo usando o padrão var em instruções switch case:
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
Neste exemplo, o padrão de variável (x, y) captura as coordenadas do ponto, permitindo diferentes transformações com base em seus valores.
Em um padrão var, o tipo da variável declarada é inferido a partir do tipo da expressão que está sendo comparada com o padrão em tempo de compilação.
O padrão var oferece uma maneira conveniente de lidar com vários cenários em que o tipo específico de expressão não é conhecido antecipadamente, melhorando a clareza e a flexibilidade do código.
Apresentando a Biblioteca IronPDF
IronPDF Document Rendering é uma biblioteca da Iron Software especializada na geração de documentos PDF. Para começar, o primeiro passo é instalar a biblioteca a partir do gerenciador de pacotes NuGet ou do gerenciador de pacotes do Visual Studio.
# To install from the NuGet Package Manager Console
Install-Package IronPdf
# To install from the NuGet Package Manager Console
Install-Package IronPdf
A imagem abaixo mostra como instalar a partir do Guia de Instalação do Visual Studio .

No código abaixo, veremos como gerar um documento PDF simples:
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
Saída

Detalhes do código
Aqui estamos usando a classe ChromePdfRenderer do IronPDF para salvar a string HTML em um documento PDF. O resultado é salvo no documento "output.pdf".
Licença de teste
O IronPDF pode ser usado com uma licença de avaliação obtida na página de licenciamento do IronPDF . Forneça um endereço de e-mail para gerar uma chave de licença que será enviada para o seu e-mail.
"IronPdf.LicenseKey": "<Your Key>"
"IronPdf.LicenseKey": "<Your Key>"
"IronPdf.LicenseKey" = "<Your Key>"
Insira a chave de licença no arquivo appsettings.json conforme mostrado acima.
Conclusão
Em C#, as expressões de correspondência de padrões oferecem uma maneira poderosa e flexível de escrever instruções condicionais, verificações de tipo e desconstruções de objetos de forma concisa e legível. Ao aproveitar o casamento de padrões, os desenvolvedores podem aprimorar a clareza e a facilidade de manutenção de seu código, reduzindo o código repetitivo e a redundância. Seja para verificação de tipos, instruções switch ou desconstrução, as expressões de correspondência de padrões fornecem um conjunto de ferramentas versátil para lidar com uma ampla gama de tarefas de programação em C#.
Em resumo, dominar expressões de correspondência de padrões pode melhorar significativamente suas habilidades de programação em C#, permitindo que você escreva um código mais limpo, expressivo e fácil de entender e manter. Também abordamos os recursos de geração de PDF a partir de HTML do IronPDF , que podem ser utilizados para gerar documentos PDF.
Perguntas frequentes
Como posso usar o casamento de padrões para melhorar a legibilidade do código em C#?
O casamento de padrões em C# permite que os desenvolvedores escrevam código mais conciso e expressivo, tornando as instruções condicionais mais claras e fáceis de entender. Isso melhora a legibilidade e a manutenção, reduzindo a complexidade dos blocos de código.
Quais são os diferentes tipos de expressões de correspondência de padrões disponíveis em C#?
C# suporta várias expressões de correspondência de padrões, incluindo expressões is , instruções switch e expressões switch . Cada tipo fornece maneiras diferentes de avaliar expressões e executar código com base na correspondência de padrões.
Como posso gerar documentos PDF usando C#?
Você pode usar o IronPDF, uma biblioteca da Iron Software, para gerar documentos PDF em C#. Ele permite a conversão de conteúdo HTML para PDF e é facilmente instalado via NuGet, oferecendo uma ampla gama de recursos para geração de PDFs.
O que são padrões de declaração e de tipo no casamento de padrões em C#?
Em C#, os padrões de declaração e tipagem verificam se o tipo de tempo de execução de uma expressão corresponde a um tipo especificado e permitem a declaração de uma nova variável local quando a correspondência é bem-sucedida, facilitando operações com segurança de tipos.
Como funcionam os padrões de constantes em C#?
Em C#, os padrões constantes são usados para verificar se uma expressão é igual a um valor constante específico, como um número inteiro ou uma string, e executar determinada lógica caso uma correspondência seja encontrada, permitindo comparações diretas de valores constantes.
Qual é a finalidade dos padrões relacionais em C#?
Em C#, os padrões relacionais permitem comparar expressões com constantes usando operadores relacionais como < , > , <= e >= . Isso é útil para implementar verificações de intervalo concisas em seu código.
Como aplicar padrões lógicos em C#?
Em C#, os padrões lógicos combinam outros padrões usando operadores lógicos, como and , or e not , permitindo condições complexas de correspondência de padrões que podem avaliar vários critérios simultaneamente.
O que é o padrão de descarte em C# e quando ele é usado?
O padrão de descarte em C#, representado por _ , corresponde a qualquer expressão, incluindo null , e é comumente usado em situações onde valores específicos precisam ser ignorados, como em expressões switch .
Como os padrões de propriedade podem ser utilizados em C#?
Em C#, os padrões de propriedade permitem que os desenvolvedores comparem as propriedades ou campos de um objeto com padrões aninhados, oferecendo uma maneira de realizar verificações profundas na estrutura de um objeto, mantendo um código claro e conciso.




