C# Unión Discriminada (Cómo Funciona para Desarrolladores)
Uniones Discriminadas, también conocidas como uniones etiquetadas o tipos suma, representan una herramienta poderosa para modelar datos que pueden tomar diferentes formas, pero con casos posibles bien definidos y limitados. Aunque C# no tiene uniones discriminadas nativas como otros lenguajes (por ejemplo, F# o Rust), se pueden simular usando varias técnicas en el lenguaje. En este tutorial, profundizaremos en las uniones discriminadas, cómo implementarlas en C#, y su caso de uso práctico con la biblioteca IronPDF.
¿Qué es una unión discriminada?
En términos simples, una unión discriminada es un tipo que puede contener una de varias formas o valores predefinidos. Proporciona una manera de crear una estructura de tipo seguro que encapsula diferentes tipos o valores mientras asegura en tiempo de compilación que solo se manejen casos válidos.
Imagina un escenario en el que quieres representar el resultado de una operación. La operación puede tener éxito, devolviendo algunos datos, o fallar, devolviendo un mensaje de error. Una unión discriminada te permitiría representar estos dos posibles resultados en un solo tipo.
Ejemplo: Simulación de Unión Discriminada en C#
Aquí tienes un ejemplo de cómo puedes simular una unión discriminada en C# usando una estructura de clase:
// 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);
}// 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);
}' Define an abstract base class representing the operation result.
Public MustInherit Class OperationResult(Of T)
' Private constructor to ensure the class cannot be instantiated directly.
Private Sub New()
End Sub
' Nested class representing a successful operation result.
Public NotInheritable Class Success
Inherits OperationResult(Of T)
Public ReadOnly Property Value() As T
Public Sub New(ByVal value As T)
Me.Value = value
End Sub
Public Overrides Function ToString() As String
Return $"Success: {Value}"
End Function
End Class
' Nested class representing a failed operation result.
Public NotInheritable Class Failure
Inherits OperationResult(Of T)
Public ReadOnly Property [Error]() As String
Public Sub New(ByVal [error] As String)
Me.Error = [error]
End Sub
Public Overrides Function ToString() As String
Return $"Failure: {[Error]}"
End Function
End Class
' Factory method to create a successful operation result.
Public Shared Function CreateSuccess(ByVal value As T) As OperationResult(Of T)
Return New Success(value)
End Function
' Factory method to create a failed operation result.
Public Shared Function CreateFailure(ByVal [error] As String) As OperationResult(Of T)
Return New Failure([error])
End Function
End ClassEn este ejemplo, OperationResult es una clase abstracta que representa nuestro tipo de unión discriminada. Puede ser un Success con un valor de tipo T o un Failure con un mensaje de error. El constructor privado asegura que las instancias de dicha clase solo puedan crearse a través de los casos predefinidos.
Uso de la concordancia de patrones con uniones discriminadas
C# proporciona potentes capacidades de coincidencia de patrones que funcionan bien con uniones discriminadas. Extendamos nuestro ejemplo de OperationResult con un método que maneje diferentes casos usando una expresión de conmutación.
// 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.
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")
' };La expresión de conmutación aquí maneja tanto los casos Success como Failure del OperationResult<int>. Esto asegura que todos los posibles casos se cubran en tiempo de compilación, proporcionando seguridad de tipos y reduciendo el riesgo de errores en tiempo de ejecución.
Métodos de extensión para uniones discriminadas
Puedes extender la funcionalidad de las uniones discriminadas usando métodos de extensión. Por ejemplo, creemos un método de extensión para nuestro OperationResult para determinar si el resultado es un éxito:
// 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<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<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 si el resultado es una instancia del caso Success.
Soporte nativo para uniones discriminadas en C#
C# no tiene soporte nativo para uniones discriminadas como algunos otros lenguajes, pero hay discusiones en curso en la comunidad sobre la adición de dicha característica. Las uniones discriminadas nativas harían más fácil definir y trabajar con tipos de unión sin la necesidad de depender de jerarquías de clases.
Errores del compilador y seguridad de tipos
Uno de los beneficios clave de las uniones discriminadas es la seguridad de tipos que proporcionan. Dado que todos los posibles casos se conocen en tiempo de compilación, el compilador puede hacer cumplir que todos los casos sean manejados. Esto lleva a menos errores en tiempo de ejecución y hace que el código sea menos propenso a errores.
Por ejemplo, si olvidas manejar un caso específico en una instrucción switch, el compilador producirá un error, incitándote a abordar el caso faltante. Esto es especialmente útil cuando se trata de estructuras de datos complejas con múltiples casos posibles.
Uso de IronPDF con uniones discriminadas en C#

IronPDF es una biblioteca de PDF para C# que ayuda a los desarrolladores a crear archivos PDF desde HTML y les permite modificar archivos PDF sin ningún problema. Al trabajar con PDFs en C#, puedes integrar IronPDF con uniones discriminadas para manejar diferentes escenarios al generar o procesar archivos PDF. Por ejemplo, podrías tener un proceso que o bien genere exitosamente un PDF o encuentre un error. Las uniones discriminadas te permiten modelar claramente este proceso. Creamos un ejemplo simple donde generamos un PDF usando IronPDF y devolvemos el resultado como una unión 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.
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(ByVal 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(ByVal 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(ByVal pdf As PdfDocument) As PdfResult
Return New Success(pdf)
End Function
' Factory method to create a failed PDF result.
Public Shared Function CreateFailure(ByVal 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(ByVal 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 ClassLa clase PdfResult representa una unión discriminada con dos casos: Success y Failure. El caso Success contiene un PdfDocument, mientras que el caso Failure contiene un mensaje de error. El método GeneratePdf toma una cadena HTML, intenta generar un PDF usando IronPDF, y devuelve el resultado como un PdfResult. Si la generación de PDF tiene éxito, devuelve el caso Success con el PDF generado. Si ocurre una excepción, devuelve el caso Failure con el mensaje de error.
Conclusión

Las uniones discriminadas en C# proporcionan una manera poderosa y flexible de modelar datos con múltiples posibles casos. Aunque C# no soporta uniones discriminadas, puedes simularlas usando jerarquías de clases, coincidencia de patrones y otras técnicas. El código resultante es más seguro en términos de tipado, menos propenso a errores y más fácil de mantener.
IronPDF proporciona una prueba gratuita para ayudarte a probar el software sin ningún costo inicial. Puedes explorar todas las características y ver cómo se alinean con tus necesidades. Después de tu prueba, las licencias están disponibles a partir de $799.
Preguntas Frecuentes
¿Cómo puedo crear una unión discriminada en C#?
Puedes crear una unión discriminada en C# definiendo una clase abstracta con subclases anidadas. Cada subclase representa un caso posible, como un estado de éxito o de error, y puedes usar el emparejamiento de patrones para manejar estos casos.
¿Cuál es el papel de la biblioteca de IronPDF en el manejo de uniones discriminadas?
La biblioteca de IronPDF se puede utilizar junto con uniones discriminadas para gestionar los resultados de generación de PDF. Al modelar estos resultados como uniones discriminadas, puedes asegurar la seguridad de tipos y manejar tanto las creaciones de PDF exitosas como cualquier error que ocurra.
¿Cómo mejora el emparejamiento de patrones las uniones discriminadas en C#?
El emparejamiento de patrones mejora las uniones discriminadas en C# al permitir a los desarrolladores manejar elegantemente cada caso posible. Con el emparejamiento de patrones, puedes gestionar de forma segura diferentes resultados, asegurando que todos los escenarios estén cubiertos en tiempo de compilación.
¿Por qué son beneficiosas las uniones discriminadas para la generación de PDF en C#?
Las uniones discriminadas son beneficiosas para la generación de PDF en C# porque proporcionan una manera estructurada de manejar casos de éxito y error. Este enfoque asegura que los problemas potenciales se aborden en tiempo de compilación, reduciendo los errores en tiempo de ejecución durante la creación del PDF.
¿Pueden las uniones discriminadas extenderse para funcionalidad adicional en C#?
Sí, las uniones discriminadas pueden extenderse con funcionalidad adicional usando métodos de extensión. Esto te permite agregar comportamientos personalizados, como verificar el estado de éxito de una generación de PDF, sin alterar la estructura base.
¿Existe una manera de simular uniones discriminadas en C# sin soporte nativo?
Sí, aunque C# no tiene soporte nativo para uniones discriminadas, se pueden simular usando jerarquías de clases. Una clase base abstracta puede usarse con clases anidadas para representar diferentes salidas posibles, como casos de éxito o fracaso.
¿Cómo manejan los desarrolladores de C# errores en la generación de PDF?
Los desarrolladores de C# pueden manejar los errores en la generación de PDF de manera efectiva usando uniones discriminadas para modelar los resultados potenciales. Este enfoque asegura que los errores se aborden en tiempo de compilación, mejorando la fiabilidad y mantenibilidad del código.
¿Cuáles son las ventajas de usar IronPDF con uniones discriminadas para proyectos en C#?
Usar IronPDF con uniones discriminadas en proyectos de C# ofrece la ventaja de un manejo robusto de errores durante la generación de PDF. Esta combinación permite una clara distinción entre operaciones exitosas y errores, mejorando la seguridad y fiabilidad del código.
¿Cómo contribuyen las uniones discriminadas a la seguridad de tipos en C#?
Las uniones discriminadas contribuyen a la seguridad de tipos en C# asegurando que todos los casos potenciales sean manejados durante la compilación. Esto reduce la probabilidad de errores en tiempo de ejecución y hace que el código sea más predecible y fácil de mantener.








