C# Discriminated Union(開発者向けの仕組み)
識別されたユニオン、別名タグ付きユニオンまたは和型は、異なる形を取る可能性があるデータをモデル化するための強力なツールを表しますが、明確に定義された限られた可能性のあるケースを持っています。 C# は F# や Rust などの他の言語のようにネイティブな識別和タイプを持っていませんが、いくつかの技術を使って言語内で識別和タイプをシミュレートすることができます。 このチュートリアルでは、識別和タイプに踏み込み、C# での実装方法と、IronPDF ライブラリを使った実用的な使用例を紹介します。
識別和タイプとは?
簡単に言えば、識別和タイプとは、いくつかの事前定義された形式または値を保持できるタイプです。 これは、異なるタイプまたは値をカプセル化し、コンパイル時に有効なケースのみが処理されることを確保した型安全な構造を作成する方法を提供します。
ある操作の結果を表現したいシナリオを想像してみてください。 操作は成功していくつかのデータを返すか、または失敗してエラーメッセージを返すことができます。 識別和タイプは、これら2つの可能な結果を単一のタイプで表現することを可能にします。
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> は区分された共用体型を表す抽象クラスです。 それは、型 T の値を持つ Success またはエラーメッセージを持つ Failure のいずれかです。 プライベートコンストラクタは、そのようなクラスのインスタンスが事前定義されたケースを通じてのみ作成されることを保証します。
パターンマッチングと識別和タイプの使用
C# は識別和タイプとうまく連携する強力なパターンマッチング機能を提供します。 スイッチ式を使用して異なるケースを処理するメソッドでOperationResult<t> の例を拡張しましょう。
// 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")
' };ここでのスイッチ式は Success と Failure ケースの両方を 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 ClassPdfResult クラスは、Success と Failure の2つのケースを持つ区分された共用体を表します。 Success ケースは PdfDocument を含み、Failure ケースはエラーメッセージを含みます。 GeneratePdf メソッドはHTML文字列を受け取り、IronPDFを使用してPDFを生成しようとし、PdfResult として結果を返します。 PDF生成が成功すると、生成されたPDFを含む Success ケースを返します。 例外が発生した場合は、エラーメッセージを含む Failure ケースを返します。
結論
C# の識別和タイプは、複数の可能なケースを持つデータをモデル化する強力で柔軟な方法を提供します。 C# は識別和タイプをサポートしていませんが、クラスの階層、パターンマッチング、その他の技術を使ってそれらをシミュレートできます。 結果として得られるコードは、型安全で、エラーが発生しにくく、メンテナンスが容易です。
IronPDF は、前払い費用なしでソフトウェアを体験するのに役立つ無料トライアルを提供します。 すべての機能を探索して、それらがあなたのニーズにどのように一致しているかを確認することができます。 トライアル後、ライセンスは $999 から利用可能です。
ジェイコブ・メラーはIron Softwareの最高技術責任者(CTO)であり、C# PDFテクノロジーを開拓する先見的なエンジニアです。Iron Softwareのコアコードベースを支えるオリジナル開発者として、彼は創業以来、会社の製品アーキテクチャを形成し、CEOのCameron Rimingtonとともに、会社をNASA、Tesla、および世界的な政府機関にサービスを提供する50人以上の会社に変えました。1999年にロンドンで最初のソフトウェアビジネスを開業し、2005年に最初 for .NETコンポーネントを作成した後、Microsoftのエコシステム全体で複雑な問題を解決することを専門としました。