跳過到頁腳內容
.NET幫助

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

區分的統一,也稱為標記的統一或總和類型,代表了一種強大的工具,可用來建模資料,這些資料可以有不同的形式,但具有定義明確且有限的可能情況。 雖然 C# 並不像某些其他語言 (例如 F# 或 Rust) 般有原生的判別式結合,但您可以使用語言中的幾種技術模擬判別式結合。 在本教程中,我們將深入介紹區分聯合、如何在 C# 中實作,以及其與 IronPDF 函式庫的實際使用案例。

什麼是判別聯合?

簡單來說,識別聯盟是一種類型,可以容納多種預定義的形式或值中的一種。 它提供了一種建立類型安全結構的方法,可以封裝不同的類型或值,同時在編譯時確保只處理有效的情況。

想像一下您想要表示操作結果的情況。 操作可能成功,返回一些資料,也可能失敗,返回錯誤訊息。 判別式合併將允許您在單一類型中表示這兩種可能的結果。

範例:在 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> 是抽象類,代表我們的可區分聯合類型。 它可以是 Success,其值為 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 表達式處理 SuccessFailure 兩種情況。 這可確保在編譯時涵蓋所有可能的情況,提供類型安全並降低執行時出錯的風險。

判別式 Unions 的擴充方法

您可以使用擴充方法來擴充判別聯合的功能。 例如,讓我們為 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 情況的實例。

C# 中對判別聯合的原生支援

C# 並不像某些其他語言一樣,原生支援識別合一,但社群中一直在討論增加此功能。 本機區分的聯合將使定義和使用聯合類型變得更容易,而不需要依賴類的層次結構。

編譯器錯誤與類型安全

判別式結合的主要優點之一是其提供的類型安全性。由於在編譯時已知道所有可能的情況,因此編譯器可以強制處理所有情況。 這可減少執行時的錯誤,並使程式碼不易出錯。

例如,如果您忘記處理 switch 語句中的特定 case,編譯器會產生錯誤,提示您處理遺漏的 case。 這在處理具有多種可能情況的複雜資料結構時尤其有用。

在 C# 中搭配判別聯合使用 IronPDF

C# Discriminated Union (How It Works For Developers):圖 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

PdfResult 類別表示一個可區分的聯合,包含兩個案例:SuccessFailureSuccess 案例包含 PdfDocument 案例,而 Failure 案例包含錯誤訊息。 GeneratePdf 方法接受一個 HTML 字串,嘗試使用 IronPDF 產生 PDF,並將結果作為 PdfResult 傳回。 如果 PDF 產生成功,則傳回 Success 情況以及產生的 PDF。 如果發生異常,則傳回 Failure 情況並附帶錯誤訊息。

結論

C# Discriminated Union (How It Works For Developers):圖 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核心代碼庫的原始開發者,他自公司成立以來就塑造了公司的產品架構,並與CEO Cameron Rimington將公司轉型為服務NASA、Tesla以及全球政府機構的50多人公司。

Jacob擁有曼徹斯特大學土木工程一級榮譽學士學位(1998年–2001年)。他於1999年在倫敦開立首家軟體公司,並於2005年建立了他的第一個.NET組件,專注於解決Microsoft生態系統中的複雜問題。

他的旗艦作品IronPDF和Iron Suite .NET程式庫全球已獲得超過3000萬次NuGet安裝,他的基礎代碼不斷在全球各地驅動開發者工具。擁有25年以上的商業經驗和41年的編碼專業知識,Jacob仍然專注於推動企業級C#、Java和Python PDF技術的創新,同時指導下一代技術領導者。

鋼鐵支援團隊

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