.NET-HILFE

C# Discriminated Union (Wie es für Entwickler funktioniert)

Veröffentlicht 23. Oktober 2024
Teilen Sie:

Benachteiligte Gewerkschaftendie auch als "tagged unions" oder "sum types" bezeichneten Typen stellen ein leistungsfähiges Werkzeug zur Modellierung von Daten dar, die verschiedene Formen annehmen können, jedoch mit klar definierten und begrenzten möglichen Fällen. Obwohl C# nicht wie einige andere Sprachen über native diskriminierte Unions verfügt(z. B. F# oder Rust)in der Sprache können Sie diskriminierte Vereinigungen mit verschiedenen Techniken simulieren. In diesem Tutorial werden wir in diskriminierte Unions eintauchen, wie man sie in C# implementiert und ihren praktischen Anwendungsfall mit demIronPDF-Bibliothek.

Was ist eine Discriminated Union?

Einfach ausgedrückt, ist eine diskriminierte Vereinigung ein Typ, der eine von mehreren vordefinierten Formen oder Werten enthalten kann. Es bietet eine Möglichkeit, eine typsichere Struktur zu erstellen, die verschiedene Typen oder Werte kapselt und gleichzeitig zur Kompilierungszeit sicherstellt, dass nur gültige Fälle behandelt werden.

Stellen Sie sich ein Szenario vor, in dem Sie das Ergebnis einer Operation darstellen möchten. Der Vorgang kann entweder erfolgreich sein und einige Daten zurückgeben oder fehlschlagen und eine Fehlermeldung zurückgeben. Eine diskriminierte Vereinigung würde es Ihnen ermöglichen, diese beiden möglichen Ergebnisse in einem einzigen Typ darzustellen.

Beispiel: Simulation von Discriminated Union in C##

Hier ist ein Beispiel dafür, wie Sie eine diskriminierte Vereinigung in C# mit einer Klassenstruktur simulieren können:

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#

In diesem Beispiel, OperationResultist eine abstrakte Klasse, die unseren diskriminierten Vereinigungstyp darstellt. Es kann entweder ein Erfolg mit einem Wert vom Typ T oder ein Misserfolg mit einer Fehlermeldung sein. Der private Konstruktor sorgt dafür, dass Instanzen einer solchen Klasse nur über die vordefinierten Fälle erstellt werden können.

Verwendung von Pattern Matching mit Discriminated Unions

C# bietet leistungsstarke Pattern-Matching-Funktionen, die gut mit diskriminierten Unions funktionieren. Erweitern wir unser OperationResultbeispiel mit einer Methode, die verschiedene Fälle mit einem Switch-Ausdruck behandelt.

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#

Der switch-Ausdruck hier behandelt sowohl den Erfolgs- als auch den Misserfolgsfall des OperationResult. Dadurch wird sichergestellt, dass alle möglichen Fälle zur Kompilierzeit abgedeckt werden, was Typsicherheit bietet und das Risiko von Laufzeitfehlern verringert.

Erweiterungsmethoden für Discriminated Unions

Sie können die Funktionalität von discriminated unions mit Erweiterungsmethoden erweitern. Lassen Sie uns zum Beispiel eine Erweiterungsmethode für unser OperationResult erstellenum festzustellen, ob das Ergebnis ein Erfolg ist:

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#

Diese öffentliche statische bool-Methode prüft, ob das Ergebnis eine Instanz des Falls Success ist.

Native Unterstützung für diskriminierte Unions in C#

C# hat keine native Unterstützung für diskriminierte Unions wie einige andere Sprachen, aber es gibt laufende Diskussionen in der Gemeinschaft über das Hinzufügen einer solchen Funktion. Native diskriminierte Unions würden es einfacher machen, Union-Typen zu definieren und mit ihnen zu arbeiten, ohne sich auf Klassenhierarchien verlassen zu müssen.

Compiler-Fehler und Typsicherheit

Einer der Hauptvorteile von diskriminierten Gewerkschaften ist die Art der Sicherheit, die sie bieten. Da alle möglichen Fälle zur Kompilierungszeit bekannt sind, kann der Compiler erzwingen, dass alle Fälle behandelt werden. Dies führt zu weniger Laufzeitfehlern und macht den Code weniger fehleranfällig.

Wenn Sie beispielsweise vergessen, einen bestimmten Fall in einer switch-Anweisung zu behandeln, gibt der Compiler einen Fehler aus und fordert Sie auf, den fehlenden Fall zu behandeln. Dies ist besonders nützlich, wenn es um komplexe Datenstrukturen mit mehreren möglichen Fällen geht.

Verwendung von IronPDF mit diskriminierten Unions in C#;

C# Discriminated Union(Wie es für Entwickler funktioniert): Abbildung 1 - IronPDF

IronPDF ist eine C# PDF-Bibliothek, die Entwicklern hilftpDF-Dateien aus HTML erstellen und ermöglicht es ihnen, PDF-Dateien mühelos zu ändern. Wenn Sie mit PDFs in C# arbeiten, können Sie IronPDF mit diskriminierten Unions integrieren, um verschiedene Szenarien bei der Erzeugung oder Verarbeitung von PDF-Dateien zu behandeln. Ein Beispiel: Sie haben einen Prozess, der entweder erfolgreich eine PDF-Datei generiert oder bei dem ein Fehler auftritt. Mit diskriminierten Unions können Sie diesen Prozess klar modellieren. Lassen Sie uns ein einfaches Beispiel erstellen, bei dem wir mit IronPDF eine PDF-Datei erzeugen und das Ergebnis als diskriminierte Vereinigung zurückgeben.

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#

Die Klasse PdfResult stellt eine diskriminierte Vereinigung mit zwei Fällen dar: Erfolg und Misserfolg. Der Erfolgsfall enthält ein PdfDocument, während der Misserfolgsfall eine Fehlermeldung enthält. Die GeneratePdf-Methode nimmt eine HTML-Zeichenkette entgegen, versucht, mit IronPDF eine PDF-Datei zu erzeugen, und gibt das Ergebnis als PdfResult zurück. Wenn die PDF-Generierung erfolgreich ist, wird der Erfolgsfall mit der generierten PDF-Datei zurückgegeben. Wenn eine Ausnahme auftritt, wird der Fehlerfall mit einer Fehlermeldung zurückgegeben.

Schlussfolgerung

C# Discriminated Union(Wie es für Entwickler funktioniert): Abbildung 2 - Lizenzierung

Discriminated Unions in C# bieten eine leistungsstarke und flexible Möglichkeit, Daten mit mehreren möglichen Fällen zu modellieren. Obwohl C# keine diskriminierten Unions unterstützt, können Sie diese mit Klassenhierarchien, Mustervergleichen und anderen Techniken simulieren. Der resultierende Code ist typsicherer, weniger fehleranfällig und leichter zu warten.

IronPDF bietet einekostenloser Test um Ihnen zu helfen, ein Gefühl für die Software zu bekommen, ohne dass Sie etwas dafür bezahlen müssen. Sie können alle Funktionen erkunden und sehen, wie sie Ihren Bedürfnissen entsprechen. Nach Ihrer Testphase sind Lizenzen ab $749 erhältlich.

< PREVIOUS
C# HttpClient (Wie es für Entwickler funktioniert)
NÄCHSTES >
C# New GUID (Wie es für Entwickler funktioniert)

Sind Sie bereit, loszulegen? Version: 2024.12 gerade veröffentlicht

Gratis NuGet-Download Downloads insgesamt: 11,810,873 Lizenzen anzeigen >