AIDE .NET

C# Discriminated Union (Comment ça marche pour les développeurs)

Publié octobre 23, 2024
Partager:

Syndicats discriminésles types d'union et de somme, également connus sous le nom de tagged unions ou sum types, représentent un outil puissant pour modéliser des données qui peuvent prendre différentes formes, mais avec des cas possibles bien définis et limités. Bien que C# ne dispose pas d'unions discriminées natives comme certains autres langages(par exemple, F# ou Rust)en ce qui concerne les unions discriminées, vous pouvez simuler des unions discriminées à l'aide de plusieurs techniques de la langue. Dans ce tutoriel, nous allons nous plonger dans les unions discriminées, la façon de les mettre en œuvre en C#, et leur cas d'utilisation pratique avec l'applicationBibliothèque IronPDF.

Qu'est-ce qu'un syndicat discriminé ?

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

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

Exemple : Simulation de l'union discriminée dans C# ;

Voici un exemple de simulation d'une union discriminée en C# à l'aide d'une structure de classe :

public abstract class OperationResult<T>
{
    private OperationResult() { }
    public sealed class Success : OperationResult<T>
    {
        public T Value { get; }
        public Success(T value) => Value = value;
        public override string ToString() => $"Success: {Value}";
    }
    public sealed class Failure : OperationResult<T>
    {
        public string Error { get; }
        public Failure(string error) => Error = error;
        public override string ToString() => $"Failure: {Error}";
    }
    public static OperationResult<T> CreateSuccess(T value) => new Success(value);
    public static OperationResult<T> CreateFailure(string error) => new Failure(error);
}
public abstract class OperationResult<T>
{
    private OperationResult() { }
    public sealed class Success : OperationResult<T>
    {
        public T Value { get; }
        public Success(T value) => Value = value;
        public override string ToString() => $"Success: {Value}";
    }
    public sealed class Failure : OperationResult<T>
    {
        public string Error { get; }
        public Failure(string error) => Error = error;
        public override string ToString() => $"Failure: {Error}";
    }
    public static OperationResult<T> CreateSuccess(T value) => new Success(value);
    public static OperationResult<T> CreateFailure(string error) => new Failure(error);
}
Public MustInherit Class OperationResult(Of T)
	Private Sub New()
	End Sub
	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
	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
	Public Shared Function CreateSuccess(ByVal value As T) As OperationResult(Of T)
		Return New Success(value)
	End Function
	Public Shared Function CreateFailure(ByVal [error] As String) As OperationResult(Of T)
		Return New Failure([error])
	End Function
End Class
VB   C#

Dans cet exemple, OperationResultest une classe abstraite qui représente notre type d'union discriminée. Il peut s'agir d'un succès avec une valeur de type T ou d'un échec avec un message d'erreur. Le constructeur privé garantit que les instances d'une telle classe ne peuvent être créées que dans les cas prédéfinis.

Utilisation de la correspondance des formes avec les unions discriminées

C# offre de puissantes capacités de recherche de motifs qui fonctionnent bien avec les unions discriminées. Étendons notre OperationResultl'exemple suivant illustre une méthode qui traite différents cas à l'aide d'une expression de type "switch".

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")
    };
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")
    };
'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")
'	};
VB   C#

L'expression switch utilisée ici traite à la fois les cas de réussite et d'échec du résultat de l'opération (OperationResult). Cela permet de s'assurer que tous les cas possibles sont couverts au moment de la compilation, ce qui garantit la sécurité des types et réduit le risque d'erreurs au moment de l'exécution.

Méthodes d'extension pour les unions discriminées

Vous pouvez étendre la fonctionnalité des unions discriminées à l'aide de méthodes d'extension. Par exemple, créons une méthode d'extension pour notre OperationResultl'objectif est de déterminer si le résultat est une réussite :

public static class OperationResultExtensions
{
    public static bool IsSuccess<T>(this OperationResult<T> result) =>
        result is OperationResult<T>.Success;
}
public static class OperationResultExtensions
{
    public static bool IsSuccess<T>(this OperationResult<T> result) =>
        result is OperationResult<T>.Success;
}
Public Module OperationResultExtensions
	<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
VB   C#

Cette méthode bool statique publique vérifie si le résultat est une instance du cas Success.

Prise en charge native des unions discriminées dans C# ;

C# ne dispose pas d'une prise en charge native des unions discriminées comme certains autres langages, mais des discussions sont en cours au sein de la communauté pour l'ajout d'une telle fonctionnalité. Les unions discriminées natives faciliteraient la définition et l'utilisation des types d'union sans devoir recourir aux hiérarchies de classes.

Erreurs de compilation et sécurité des types

L'un des principaux avantages des syndicats discriminés est le type de sécurité qu'ils offrent. Comme tous les cas possibles sont connus au moment de la compilation, le compilateur peut s'assurer que tous les cas sont traités. Cela permet de réduire le nombre d'erreurs d'exécution et de rendre 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 invitant à traiter le cas manquant. Cela est particulièrement utile lorsqu'il s'agit de structures de données complexes avec de multiples cas possibles.

Utilisation d'IronPDF avec des Unions Discriminées dans C&num ;

Union discriminée en C#(Comment ça marche pour les développeurs) : Figure 1 - IronPDF

IronPDF est une bibliothèque PDF C# qui aide les développeurs àcréer des fichiers PDF à partir de HTML la traduction doit rester professionnelle et préserver l'exactitude technique tout en expliquant les caractéristiques et les avantages de ces outils de développement. Lorsque vous travaillez avec des PDF en C#, vous pouvez intégrer IronPDF avec des unions discriminées pour gérer différents scénarios lors de la génération ou du traitement de fichiers PDF. Par exemple, vous pouvez avoir un processus qui génère un PDF avec succès ou qui rencontre une erreur. Les unions discriminées vous permettent de modéliser clairement ce processus. Créons un exemple simple dans lequel nous générons un PDF à l'aide d'IronPDF et renvoyons le résultat sous la forme d'une union discriminée.

using IronPdf;
using System;
public abstract class PdfResult
{
    private PdfResult() { }
    public sealed class Success : PdfResult
    {
        public PdfDocument Pdf { get; }
        public Success(PdfDocument pdf) => Pdf = pdf;
        public override string ToString() => "PDF generation succeeded";
    }
    public sealed class Failure : PdfResult
    {
        public string ErrorMessage { get; }
        public Failure(string errorMessage) => ErrorMessage = errorMessage;
        public override string ToString() => $"PDF generation failed: {ErrorMessage}";
    }
    public static PdfResult CreateSuccess(PdfDocument pdf) => new Success(pdf);
    public static PdfResult CreateFailure(string errorMessage) => new Failure(errorMessage);
}
public class PdfGenerator
{
    public PdfResult GeneratePdf(string htmlContent)
    {
        try
        {
            var renderer = new ChromePdfRenderer();
            var pdf = renderer.RenderHtmlAsPdf(htmlContent);
            return PdfResult.CreateSuccess(pdf);
        }
        catch (Exception ex)
        {
            return PdfResult.CreateFailure(ex.Message);
        }
    }
}
using IronPdf;
using System;
public abstract class PdfResult
{
    private PdfResult() { }
    public sealed class Success : PdfResult
    {
        public PdfDocument Pdf { get; }
        public Success(PdfDocument pdf) => Pdf = pdf;
        public override string ToString() => "PDF generation succeeded";
    }
    public sealed class Failure : PdfResult
    {
        public string ErrorMessage { get; }
        public Failure(string errorMessage) => ErrorMessage = errorMessage;
        public override string ToString() => $"PDF generation failed: {ErrorMessage}";
    }
    public static PdfResult CreateSuccess(PdfDocument pdf) => new Success(pdf);
    public static PdfResult CreateFailure(string errorMessage) => new Failure(errorMessage);
}
public class PdfGenerator
{
    public PdfResult GeneratePdf(string htmlContent)
    {
        try
        {
            var renderer = new ChromePdfRenderer();
            var pdf = renderer.RenderHtmlAsPdf(htmlContent);
            return PdfResult.CreateSuccess(pdf);
        }
        catch (Exception ex)
        {
            return PdfResult.CreateFailure(ex.Message);
        }
    }
}
Imports IronPdf
Imports System
Public MustInherit Class PdfResult
	Private Sub New()
	End Sub
	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
	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
	Public Shared Function CreateSuccess(ByVal pdf As PdfDocument) As PdfResult
		Return New Success(pdf)
	End Function
	Public Shared Function CreateFailure(ByVal errorMessage As String) As PdfResult
		Return New Failure(errorMessage)
	End Function
End Class
Public Class PdfGenerator
	Public Function GeneratePdf(ByVal htmlContent As String) As PdfResult
		Try
			Dim renderer = New ChromePdfRenderer()
			Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
			Return PdfResult.CreateSuccess(pdf)
		Catch ex As Exception
			Return PdfResult.CreateFailure(ex.Message)
		End Try
	End Function
End Class
VB   C#

La classe PdfResult représente une union discriminée avec deux cas : Succès et Échec. Le cas de réussite contient un document Pdf, tandis que le cas d'échec contient 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 renvoie le résultat sous la forme d'un PdfResult. Si la génération du PDF réussit, il renvoie le cas de réussite avec le PDF généré. Si une exception se produit, elle renvoie le cas d'échec avec le message d'erreur.

Conclusion

Union discriminée en C#(Comment ça marche pour les développeurs) : Figure 2 - Licence

Les unions discriminées en C# constituent 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 discriminées, vous pouvez les simuler en utilisant des hiérarchies de classes, la correspondance de motifs et d'autres techniques. Le code résultant est plus sûr, moins sujet aux erreurs et plus facile à maintenir.

IronPDF fournit un service deessai gratuit la traduction doit rester professionnelle, tout en préservant l'exactitude technique et en expliquant les caractéristiques et les avantages de ces outils de développement. Vous pouvez explorer toutes les fonctionnalités et voir si elles correspondent à vos besoins. Après votre essai, les licences sont disponibles à partir de 749 $.

< PRÉCÉDENT
C# HttpClient (Comment ça marche pour les développeurs)
SUIVANT >
C# New GUID (How It Works For Developers) (Nouveau GUID en C# (Comment cela fonctionne pour les développeurs))