跳至頁尾內容
開發者更新

C#差異聯合(對開發者如何理解的工作)

判別聯合,又稱標記聯合或總和型別,代表一種強大的工具,用來建模可以採用不同形式但具有定義良好且可能情況有限的資料。 雖然C#不像其他一些語言(例如,F#或Rust)那樣擁有原生的判別聯合,但您可以使用語言中的幾種技術來模擬判別聯合。 在本教程中,我們將深入探討判別聯合,如何在C#中實現它們,以及使用IronPDF程式庫的實際使用案例。

什麼是判別聯合?

簡單來說,判別聯合是一種可以包含多種預定義形式或值的型別。 它提供了一種建立型別安全結構的方法,封裝了不同型別或值,同時在編譯時確保處理的僅是有效例。

想像一下您想要表現操作結果的情境。 該操作可以成功,返回一些資料,或者失敗,返回一條錯誤消息。 判別聯合將允許您在單一型別中表示這兩種可能的結果。

Example: Simulating Discriminated Union in C

以下是如何在C#中使用類結構模擬判別聯合的範例:

// 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);
}
Imports System

' 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(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([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(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([error] As String) As OperationResult(Of T)
        Return New Failure([error])
    End Function
End Class
$vbLabelText   $csharpLabel

在此範例中,OperationResult<t>是一個抽象類,表示我們的判別聯合型別。 它可以是一個具有Failure。 私有構造函式確保此類的實例只能通過預定義案例建立。

使用判別聯合的模式匹配

C#提供強大的模式匹配功能,能與判別聯合相配合良好。 讓我們擴展OperationResult<t>例子,藉由一個使用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

此處的switch表達式處理OperationResult<int>。 這確保所有可能的案例在編譯時被覆蓋,提供型別安全性並減少運行時錯誤風險。

判別聯合的擴展方法

您可以使用擴展方法來擴展判別聯合的功能。 例如,讓我們為OperationResult<t>建立一個擴展方法來確定結果是否成功:

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

此靜態方法檢查結果是否為Success案例的實例。

Native Support for Discriminated Unions in C

C#不提供像某些其他語言那樣的判別聯合原生支持,但社群內正在進行關於新增這種功能的討論。 原生的判別聯合將使定義和使用聯合型別變得更加容易,無需依賴於類層次結構。

編譯器錯誤和型別安全

判別聯合的關鍵優勢之一是它們提供的型別安全性。由於所有可能的案例在編譯時已知,編譯器可以強制執行所有案例的處理。 這導致較少的運行時錯誤,使程式碼更不容易出錯。

例如,如果您在switch語句中忘記處理特定案例,編譯器將產生錯誤,提醒您解決遺漏的案例。 這在處理具有多個可能案例的複雜資料結構時尤其有用。

Using IronPDF with Discriminated Unions in C

C#判別聯合(開發人員的工作方式):圖1 - IronPDF

IronPDF是C#的PDF程式庫,幫助開發者從HTML建立PDF文件並允許他們輕鬆修改PDF文件。 在C#中處理PDF文件時,您可以將IronPDF與判別聯合整合以處理生成或處理PDF文件時的不同情境。 例如,您可能有一個流程,無論是成功生成PDF還是遇到錯誤。 判別聯合允許您清楚地建模此過程。 讓我們建立一個簡單的例子,在這裡我們使用IronPDF生成一個PDF並返回結果作為一個判別聯合。

// 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

FailureFailure案例則持有錯誤資訊。 PdfResult。 如果PDF生成成功,則返回包含生成的PDF的Success案例。 如果發生異常,則返回包含錯誤消息的Failure案例。

結論

C#判別聯合(開發人員的工作方式):圖2 - 授權

C#中的判別聯合提供了一種強大而靈活的方式來建模具有多個可能案例的資料。 雖然C#不支持判別聯合,您可以使用類層次結構、模式匹配和其他技術來模擬它們。 生成的程式碼更加型別安全,錯誤更少且更易於維護。

IronPDF提供免費試用,幫助您在沒有前期成本的情況下體驗軟體。 您可以探索所有功能並查看它們如何與您的需求匹配。 在您的試用期結束後,授權從$999開始提供。

常見問題

我如何在C#中建立判別聯合?

您可以通過定義帶有巢狀子類的抽象類來在C#中建立判別聯合。每個子類代表一個可能的情況,例如成功或錯誤狀態,您可以使用模式匹配來處理這些情況。

IronPDF程式庫在處理判別聯合中扮演了什麼角色?

IronPDF程式庫可以與判別聯合一起使用來管理PDF生成結果。通過將這些結果建模為判別聯合,您可以確保型別安全,並處理成功的PDF生成以及任何出現的錯誤。

模式匹配如何增強C#中的判別聯合?

模式匹配通過允許開發人員優雅地處理每個可能的情況來增強C#中的判別聯合。通過模式匹配,您可以安全地管理不同的結果,確保所有場景在編譯時都得到處理。

為什麼判別聯合對於C#中的PDF生成有益?

判別聯合對於C#中的PDF生成有益,因為它們提供了一種結構化的方法來處理成功和錯誤情況。這種方法確保潛在問題在編譯時得到解決,從而減少PDF建立過程中的運行時錯誤。

判別聯合可以在C#中擴展以增加功能嗎?

是的,判別聯合可以通過擴展方法增加額外功能。這允許您新增自定義行為,例如檢查PDF生成的成功狀態,而不改變基礎結構。

有沒有辦法在C#中模擬沒有原生支援的判別聯合?

是的,即使C#不支持原生判別聯合,也可以使用類層次結構來模擬。可以使用抽象基類與巢狀類來表示不同的可能結果,例如成功或失敗情況。

C#開發人員如何有效地處理PDF生成過程中的錯誤?

C#開發人員可以通過使用判別聯合來建模可能的結果,以有效地處理PDF生成過程中的錯誤。這種方法確保在編譯時就能解決錯誤,提高程式碼的可靠性和可維護性。

在C#專案中使用IronPDF搭配判別聯合的優點是什麼?

在C#專案中使用IronPDF搭配判別聯合提供了在PDF生成過程中強大錯誤處理的優勢。這種組合使成功操作和錯誤能夠清楚地區分,增強了程式碼的安全性和可靠性。

判別聯合如何促進C#中的型別安全性?

判別聯合通過確保所有可能情況在編譯期間得到處理來促進C#中的型別安全性。這減少了運行時錯誤的可能性,使程式碼更具可預測性並易於維護。

Jacob Mellor,首席技術官 @ Team Iron
首席技術官

Jacob Mellor是Iron Software的首席技術官,一位在C# PDF技術上開創先河的遠見工程師。作為Iron Software核心程式碼庫的原開發者,他從創立以來就一直在塑造公司的產品架構,與首席執行官Cameron Rimington一起將公司轉變為服務於NASA、特斯拉和全球政府公司的50多名人員的公司。

Jacob擁有曼徹斯特大學的土木工程一等榮譽學士學位(BEng),於1998-2001年之間獲得。在1999年於倫敦創辦他的第一家軟體公司並於2005年建立了他的第一批.NET元組件後,他專注於解決Microsoft生態系統中的複雜問題。

他的旗艦IronPDF和Iron Suite .NET程式庫在全球獲得了超過3000萬次NuGet安裝依據,他的基礎程式碼基繼續支援著世界各地開發者使用的工具。擁有25年的商業經驗和41年的程式設計專業知識,他仍專注於推動企業級C#、Java和Python PDF技術的創新,同時指導下一代技術領導者。

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話