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 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)
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' 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)
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在此範例中,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")
' };' 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")
' };此處的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' 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此靜態方法檢查結果是否為Success案例的實例。
Native Support for Discriminated Unions in C#
C#不提供像某些其他語言那樣的判別聯合原生支持,但社群內正在進行關於新增這種功能的討論。 原生的判別聯合將使定義和使用聯合型別變得更加容易,無需依賴於類層次結構。
編譯器錯誤和型別安全
判別聯合的關鍵優勢之一是它們提供的型別安全性。由於所有可能的案例在編譯時已知,編譯器可以強制執行所有案例的處理。 這導致較少的運行時錯誤,使程式碼更不容易出錯。
例如,如果您在switch語句中忘記處理特定案例,編譯器將產生錯誤,提醒您解決遺漏的案例。 這在處理具有多個可能案例的複雜資料結構時尤其有用。
Using IronPDF with Discriminated Unions in C#

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(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(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(pdf As PdfDocument) As PdfResult
Return New Success(pdf)
End Function
' Factory method to create a failed PDF result.
Public Shared Function CreateFailure(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(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' 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(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(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(pdf As PdfDocument) As PdfResult
Return New Success(pdf)
End Function
' Factory method to create a failed PDF result.
Public Shared Function CreateFailure(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(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 ClassFailure。 Failure案例則持有錯誤資訊。 PdfResult。 如果PDF生成成功,則返回包含生成的PDF的Success案例。 如果發生異常,則返回包含錯誤消息的Failure案例。
結論
C#中的判別聯合提供了一種強大而靈活的方式來建模具有多個可能案例的資料。 雖然C#不支持判別聯合,您可以使用類層次結構、模式匹配和其他技術來模擬它們。 生成的程式碼更加型別安全,錯誤更少且更易於維護。
IronPDF提供免費試用,幫助您在沒有前期成本的情況下體驗軟體。 您可以探索所有功能並查看它們如何與您的需求匹配。 在您的試用期結束後,授權從$999開始提供。
Jacob Mellor是Iron Software的首席技術官,一位在C# PDF技術上開創先河的遠見工程師。作為Iron Software核心程式碼庫的原開發者,他從創立以來就一直在塑造公司的產品架構,與首席執行官Cameron Rimington一起將公司轉變為服務於NASA、特斯拉和全球政府公司的50多名人員的公司。