
União discriminada em C# (como funciona para desenvolvedores)
As uniões discriminadas , também conhecidas como uniões etiquetadas ou tipos de soma, representam uma ferramenta poderosa para modelar dados que podem assumir diferentes formas, mas com casos possíveis bem definidos e limitados. Embora o C# não possua uniões discriminadas nativas como algumas outras linguagens (por exemplo, F# ou Rust), você pode simular uniões discriminadas usando diversas técnicas na linguagem. Neste tutorial, vamos explorar as uniões discriminadas, como implementá-las em C# e seu uso prático com a biblioteca IronPDF .
O que é um sindicato discriminatório?
Em termos simples, uma união discriminada é um tipo que pode assumir uma de várias formas ou valores predefinidos. Ela fornece uma maneira de criar uma estrutura com segurança de tipos que encapsula diferentes tipos ou valores, garantindo em tempo de compilação que apenas os casos válidos sejam tratados.
Imagine um cenário em que você queira representar o resultado de uma operação. A operação pode ser bem-sucedida, retornando alguns dados, ou falhar, retornando uma mensagem de erro. Uma união discriminada permitiria representar esses dois resultados possíveis em um único tipo.
Example: Simulating Discriminated Union in C#
Aqui está um exemplo de como você pode simular uma união discriminada em C# usando uma estrutura de classe:
// Define an abstract base class representing the operation result.
public abstract class OperationResult<t>
{
// Private constructor to ensure the class cannot be instantiated directly.
private OperationResult() { }
// Nested class representing a successful operation result.
public sealed class Success : OperationResult<t>
{
public T Value { get; }
public Success(T value) => Value = value;
public override string ToString() => $"Success: {Value}";
}
// Nested class representing a failed operation result.
public sealed class Failure : OperationResult<t>
{
public string Error { get; }
public Failure(string error) => Error = error;
public override string ToString() => $"Failure: {Error}";
}
// Factory method to create a successful operation result.
public static OperationResult<t> CreateSuccess(T value) => new Success(value);
// Factory method to create a failed operation result.
public static OperationResult<t> CreateFailure(string error) => new Failure(error);
}
Neste exemplo, OperationResult<t> é uma classe abstrata que representa nosso tipo de união discriminada. Pode ser um Success com um valor do tipo T ou um Failure com uma mensagem de erro. O construtor privado garante que instâncias dessa classe só possam ser criadas por meio dos casos predefinidos.
Utilizando a correspondência de padrões com uniões discriminadas
C# oferece recursos poderosos de correspondência de padrões que funcionam bem com uniões discriminadas. Vamos estender nosso exemplo OperationResult<t> com um método que lida com diferentes casos usando uma expressão switch.
// Method to handle the result using pattern matching.
public string HandleResult(OperationResult<int> result) =>
result switch
{
OperationResult<int>.Success success => $"Operation succeeded with value: {success.Value}",
OperationResult<int>.Failure failure => $"Operation failed with error: {failure.Error}",
_ => throw new InvalidOperationException("Unexpected result type")
};' Method to handle the result using pattern matching.
'INSTANT VB TODO TASK: The following 'switch expression' was not converted by Instant VB:
'public string HandleResult(OperationResult<int> result) => result switch
' {
' OperationResult<int>.Success success => $"Operation succeeded with value: {success.Value}",
' OperationResult<int>.Failure failure => $"Operation failed with error: {failure.Error}",
' _ => throw new InvalidOperationException("Unexpected result type")
' };A expressão switch aqui lida com ambos os casos Success e Failure do OperationResult<int>. Isso garante que todos os casos possíveis sejam cobertos em tempo de compilação, proporcionando segurança de tipos e reduzindo o risco de erros em tempo de execução.
Métodos de extensão para sindicatos discriminados
Você pode estender a funcionalidade de uniões discriminadas usando métodos de extensão. Por exemplo, vamos criar um método de extensão para nosso OperationResult<t> para determinar se o resultado é um sucesso:
// Static class to hold extension methods for OperationResult<t>.
public static class OperationResultExtensions
{
// Extension method to check if the operation result indicates success.
public static bool IsSuccess<t>(this OperationResult<t> result) =>
result is OperationResult<t>.Success;
}' Static class to hold extension methods for OperationResult(Of T).
Public Module OperationResultExtensions
' Extension method to check if the operation result indicates success.
<System.Runtime.CompilerServices.Extension>
Public Function IsSuccess(Of T)(ByVal result As OperationResult(Of T)) As Boolean
Return TypeOf result Is OperationResult(Of T).Success
End Function
End ModuleEste método estático verifica se o resultado é uma instância do caso Success.
Native Support for Discriminated Unions in C#
C# não possui suporte nativo para uniões discriminadas como algumas outras linguagens, mas há discussões em andamento na comunidade sobre a adição de tal recurso. Sindicatos que discriminam os nativos tornariam mais fácil definir e trabalhar com tipos de sindicatos sem precisar recorrer a hierarquias de classe.
Erros de compilação e segurança de tipos
Um dos principais benefícios das uniões discriminadas é a segurança de tipos que elas proporcionam. Como todos os casos possíveis são conhecidos em tempo de compilação, o compilador pode garantir que todos os casos sejam tratados. Isso resulta em menos erros de tempo de execução e torna o código menos propenso a erros.
Por exemplo, se você se esquecer de tratar um caso específico em uma instrução switch, o compilador produzirá um erro, solicitando que você corrija o caso ausente. Isso é especialmente útil ao lidar com estruturas de dados complexas com múltiplos casos possíveis.
Using IronPDF with Discriminated Unions in C#

IronPDF é uma biblioteca C# para PDF que ajuda desenvolvedores a criar arquivos PDF a partir de HTML e permite que eles modifiquem arquivos PDF sem complicações. Ao trabalhar com PDFs em C#, você pode integrar o IronPDF com uniões discriminadas para lidar com diferentes cenários ao gerar ou processar arquivos PDF. Por exemplo, você pode ter um processo que gera um PDF com sucesso ou que encontra um erro. Os sindicatos discriminatórios permitem que você modele esse processo de forma clara. Vamos criar um exemplo simples onde geramos um PDF usando o IronPDF e retornamos o resultado como uma união discriminada.
// Using directives for necessary namespaces.
using IronPdf;
using System;
// Define an abstract base class representing the PDF generation result.
public abstract class PdfResult
{
// Private constructor to ensure the class cannot be instantiated directly.
private PdfResult() { }
// Nested class representing a successful PDF generation result.
public sealed class Success : PdfResult
{
public PdfDocument Pdf { get; }
public Success(PdfDocument pdf) => Pdf = pdf;
public override string ToString() => "PDF generation succeeded";
}
// Nested class representing a failed PDF generation result.
public sealed class Failure : PdfResult
{
public string ErrorMessage { get; }
public Failure(string errorMessage) => ErrorMessage = errorMessage;
public override string ToString() => $"PDF generation failed: {ErrorMessage}";
}
// Factory method to create a successful PDF result.
public static PdfResult CreateSuccess(PdfDocument pdf) => new Success(pdf);
// Factory method to create a failed PDF result.
public static PdfResult CreateFailure(string errorMessage) => new Failure(errorMessage);
}
// Class to generate PDFs using IronPDF.
public class PdfGenerator
{
// Method to generate a PDF from HTML content and return the result as a PdfResult.
public PdfResult GeneratePdf(string htmlContent)
{
try
{
// Create a new ChromePdfRenderer instance.
var renderer = new ChromePdfRenderer();
// Attempt to render the HTML content as a PDF.
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
// Return a success result with the generated PDF.
return PdfResult.CreateSuccess(pdf);
}
catch (Exception ex)
{
// Return a failure result with the error message if an exception occurs.
return PdfResult.CreateFailure(ex.Message);
}
}
}' Using directives for necessary namespaces.
Imports IronPdf
Imports System
' Define an abstract base class representing the PDF generation result.
Public MustInherit Class PdfResult
' Private constructor to ensure the class cannot be instantiated directly.
Private Sub New()
End Sub
' Nested class representing a successful PDF generation result.
Public NotInheritable Class Success
Inherits PdfResult
Public ReadOnly Property Pdf As PdfDocument
Public Sub New(pdf As PdfDocument)
Me.Pdf = pdf
End Sub
Public Overrides Function ToString() As String
Return "PDF generation succeeded"
End Function
End Class
' Nested class representing a failed PDF generation result.
Public NotInheritable Class Failure
Inherits PdfResult
Public ReadOnly Property ErrorMessage As String
Public Sub New(errorMessage As String)
Me.ErrorMessage = errorMessage
End Sub
Public Overrides Function ToString() As String
Return $"PDF generation failed: {ErrorMessage}"
End Function
End Class
' Factory method to create a successful PDF result.
Public Shared Function CreateSuccess(pdf As PdfDocument) As PdfResult
Return New Success(pdf)
End Function
' Factory method to create a failed PDF result.
Public Shared Function CreateFailure(errorMessage As String) As PdfResult
Return New Failure(errorMessage)
End Function
End Class
' Class to generate PDFs using IronPDF.
Public Class PdfGenerator
' Method to generate a PDF from HTML content and return the result as a PdfResult.
Public Function GeneratePdf(htmlContent As String) As PdfResult
Try
' Create a new ChromePdfRenderer instance.
Dim renderer = New ChromePdfRenderer()
' Attempt to render the HTML content as a PDF.
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
' Return a success result with the generated PDF.
Return PdfResult.CreateSuccess(pdf)
Catch ex As Exception
' Return a failure result with the error message if an exception occurs.
Return PdfResult.CreateFailure(ex.Message)
End Try
End Function
End ClassA classe PdfResult representa uma união discriminada com dois casos: Success e Failure. O caso Success contém um PdfDocument, enquanto o caso Failure contém uma mensagem de erro. O método GeneratePdf recebe uma string HTML, tenta gerar um PDF usando IronPDF e retorna o resultado como um PdfResult. Se a geração do PDF for bem-sucedida, ele retorna o caso Success com o PDF gerado. Se ocorrer uma exceção, ele retorna o caso Failure com a mensagem de erro.
Conclusão

Em C#, as uniões discriminadas oferecem uma maneira poderosa e flexível de modelar dados com múltiplos casos possíveis. Embora o C# não suporte uniões discriminadas, você pode simulá-las usando hierarquias de classes, correspondência de padrões e outras técnicas. O código resultante é mais seguro em relação aos tipos, menos propenso a erros e mais fácil de manter.
A IronPDF oferece um período de teste gratuito para que você possa experimentar o software sem custos iniciais. Você pode explorar todas as funcionalidades e ver como elas se alinham às suas necessidades. Após o seu teste, as licenças estão disponíveis a partir de $999.

Curtis Chau é bacharel em Ciência da Computação (Universidade Carleton) e se especializa em desenvolvimento front-end, com experiência em Node.js, TypeScript, JavaScript e React. Apaixonado por criar interfaces de usuário intuitivas e esteticamente agradáveis, Curtis gosta de trabalhar com frameworks modernos e criar manuais bem estruturados e visualmente atraentes.
Artigos relacionados


