Passer au contenu du pied de page
.NET AIDE

C# Union Discriminée (Comment ça fonctionne pour les développeurs)

Unions discriminants, également connus sous le nom d'unions étiquetées ou de types somme, représentent un outil puissant pour modéliser des données pouvant prendre différentes formes, mais avec des cas possibles bien définis et limités. Bien que C# n'ait pas d'unions discriminantes natives comme certains autres langages (par exemple, F# ou Rust), vous pouvez simuler des unions discriminantes en utilisant plusieurs techniques dans le langage. Dans ce tutoriel, nous approfondirons les unions discriminantes, comment les implémenter en C#, et leur cas d'utilisation pratique avec la bibliothèque IronPDF.

Qu'est-ce qu'une Union Discriminante ?

En termes simples, une union discriminante est un type qui peut contenir l'une de plusieurs formes ou valeurs prédéfinies. Elle fournit un moyen de créer une structure typée qui encapsule différents types ou valeurs tout en garantissant que seuls les cas valides sont traités au moment de la compilation.

Imaginez un scénario où vous souhaitez représenter le résultat d'une opération. L'opération peut soit réussir en retournant des données, soit échouer en retournant un message d'erreur. Une union discriminante vous permettrait de représenter ces deux résultats possibles en un seul type.

Exemple : Simulation d'Union Discriminante en C#

Voici un exemple de la façon dont vous pouvez simuler une union discriminante en C# en utilisant une structure 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);
}
// 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 Class
$vbLabelText   $csharpLabel

Dans cet exemple, OperationResult<T> est une classe abstraite qui représente notre type d'union discriminante. Il peut être soit un Succès avec une valeur de type T, soit un Échec avec un message d'erreur. Le constructeur privé garantit que les instances de cette classe ne peuvent être créées qu'à travers les cas prédéfinis.

Utilisation de la Correspondance de Modèles avec les Unions Discriminantes

C# fournit de puissantes capacités de correspondance de modèles qui fonctionnent bien avec les unions discriminantes. Étendons notre exemple OperationResult<T> avec une méthode qui gère les différents cas à l'aide d'une expression 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.
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")
'	};
$vbLabelText   $csharpLabel

L'expression switch ici gère à la fois les cas Succès et Échec de OperationResult<int>. Cela garantit que tous les cas possibles sont couverts au moment de la compilation, offrant ainsi une sécurité de type et réduisant le risque d'erreurs à l'exécution.

Méthodes d'Extension pour les Unions Discriminantes

Vous pouvez étendre la fonctionnalité des unions discriminantes en utilisant des méthodes d'extension. Par exemple, créons une méthode d'extension pour notre OperationResult<T> afin de déterminer si le résultat est un succès :

// 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 Module
$vbLabelText   $csharpLabel

Cette méthode statique vérifie si le résultat est une instance du cas Succès.

Support Natif des Unions Discriminantes en C#

C# n'a pas de support natif pour les unions discriminantes comme certains autres langages, mais des discussions sont en cours dans la communauté pour ajouter une telle fonctionnalité. Les unions discriminantes natives rendraient plus facile la définition et le travail avec les types d'unions sans avoir besoin de s'appuyer sur des hiérarchies de classes.

Erreurs du Compilateur et Sécurité de Type

L'un des principaux avantages des unions discriminantes est la sécurité de type qu'elles procurent. Puisque tous les cas possibles sont connus au moment de la compilation, le compilateur peut imposer que tous les cas soient traités. Cela entraîne moins d'erreurs à l'exécution et rend le code moins sujet aux erreurs.

Par exemple, si vous oubliez de traiter un cas spécifique dans une instruction switch, le compilateur produira une erreur, vous incitant à résoudre le cas manquant. Cela est particulièrement utile lors de la gestion de structures de données complexes avec plusieurs cas possibles.

Utilisation d'IronPDF avec des Unions Discriminantes en C#

Union Discriminante C# (Comment cela fonctionne pour les développeurs) : Figure 1 - IronPDF

IronPDF est une bibliothèque PDF en C# qui aide les développeurs à créer des fichiers PDF à partir de HTML et leur permet de modifier les fichiers PDF sans aucune difficulté. Lors du travail avec des PDF en C#, vous pouvez intégrer IronPDF avec des unions discriminantes pour gérer différents scénarios lors de la génération ou du traitement des fichiers PDF. Par exemple, vous pourriez avoir un processus qui génère soit un PDF avec succès, soit qui rencontre une erreur. Les unions discriminantes vous permettent de modéliser ce processus clairement. Créons un exemple simple où nous générons un PDF à l'aide d'IronPDF et retournons le résultat sous forme d'union discriminante.

// 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 Class
$vbLabelText   $csharpLabel

La classe PdfResult représente une union discriminante avec deux cas : Succès et Échec. Le cas Succès contient un PdfDocument, tandis que le cas Échec détient un message d'erreur. La méthode GeneratePdf prend une chaîne HTML, tente de générer un PDF à l'aide d'IronPDF et retourne le résultat sous la forme d'un PdfResult. Si la génération du PDF réussit, elle retourne le cas Succès avec le PDF généré. Si une exception se produit, elle retourne le cas Échec avec le message d'erreur.

Conclusion

Union Discriminante C# (Comment cela fonctionne pour les développeurs) : Figure 2 - Licences

Les unions discriminantes en C# fournissent un moyen puissant et flexible de modéliser des données avec plusieurs cas possibles. Bien que C# ne prenne pas en charge les unions discriminantes, vous pouvez les simuler en utilisant des hiérarchies de classes, la correspondance de modèles et d'autres techniques. Le code résultant est plus typé, moins sujet aux erreurs et plus facile à maintenir.

IronPDF offre un essai gratuit pour vous aider à vous familiariser avec le logiciel sans frais initiaux. Vous pouvez explorer toutes les fonctionnalités et voir comment elles correspondent à vos besoins. Après votre essai, des licences sont disponibles à partir de $799.

Questions Fréquemment Posées

Comment puis-je créer une union discriminée en C# ?

Vous pouvez créer une union discriminée en C# en définissant une classe abstraite avec des sous-classes imbriquées. Chaque sous-classe représente un cas possible, tel qu'un état de succès ou d'erreur, et vous pouvez utiliser le pattern matching pour traiter ces cas.

Quel est le rôle de la bibliothèque IronPDF dans la gestion des unions discriminées?

La bibliothèque IronPDF peut être utilisée en conjonction avec les unions discriminées pour gérer les résultats de génération de PDF. En modélisant ces résultats comme des unions discriminées, vous pouvez garantir la sécurité des types et traiter à la fois les créations de PDF réussies et les erreurs éventuelles.

Comment le pattern matching améliore-t-il les unions discriminées en C# ?

Le pattern matching améliore les unions discriminées en C# en permettant aux développeurs de gérer élégamment chaque cas possible. Avec le pattern matching, vous pouvez gérer en toute sécurité différents résultats, garantissant que tous les scénarios sont couverts à la compilation.

Pourquoi les unions discriminées sont-elles bénéfiques pour la génération de PDF en C# ?

Les unions discriminées sont bénéfiques pour la génération de PDF en C# car elles offrent un moyen structuré de traiter les cas de succès et d'erreur. Cette approche garantit que les problèmes potentiels sont abordés à la compilation, réduisant ainsi les erreurs d'exécution lors de la création du PDF.

Les unions discriminées peuvent-elles être étendues pour une fonctionnalité supplémentaire en C# ?

Oui, les unions discriminées peuvent être étendues avec des fonctionnalités supplémentaires à l'aide de méthodes d'extension. Cela vous permet d'ajouter des comportements personnalisés, comme vérifier l'état de réussite d'une génération de PDF, sans modifier la structure de base.

Existe-t-il un moyen de simuler les unions discriminées en C# sans support natif?

Oui, même si C# ne prend pas en charge les unions discriminées de manière native, elles peuvent être simulées à l'aide des hiérarchies de classes. Une classe de base abstraite peut être utilisée avec des classes imbriquées pour représenter différents résultats possibles, tels que des cas de succès ou d'échec.

Comment les développeurs C# peuvent-ils gérer efficacement les erreurs lors de la génération de PDF ?

Les développeurs C# peuvent gérer efficacement les erreurs lors de la génération de PDF en utilisant des unions discriminées pour modéliser les résultats potentiels. Cette approche garantit que les erreurs sont abordées à la compilation, améliorant la fiabilité et la maintenance du code.

Quels sont les avantages d'utiliser IronPDF avec des unions discriminées pour les projets C# ?

L'utilisation d'IronPDF avec des unions discriminées dans les projets C# offre l'avantage d'une gestion robuste des erreurs lors de la génération de PDF. Cette combinaison permet de différencier clairement les opérations réussies et les erreurs, renforçant la sécurité et la fiabilité du code.

Comment les unions discriminées contribuent-elles à la sécurité des types en C# ?

Les unions discriminées contribuent à la sécurité des types en C# en garantissant que tous les cas possibles sont traités lors de la compilation. Cela réduit la probabilité d'erreurs d'exécution et rend le code plus prévisible et plus facile à maintenir.

Curtis Chau
Rédacteur technique

Curtis Chau détient un baccalauréat en informatique (Université de Carleton) et se spécialise dans le développement front-end avec expertise en Node.js, TypeScript, JavaScript et React. Passionné par la création d'interfaces utilisateur intuitives et esthétiquement plaisantes, Curtis aime travailler avec des frameworks modernes ...

Lire la suite