Struct OneOf<T1, T2, T3, T4>

Namespace
REslava.Result.AdvancedPatterns
Assembly
REslava.Result.dll

Represents a value that can be one of four possible types. A type-safe discriminated union for functional programming patterns.

public readonly struct OneOf<T1, T2, T3, T4> : IEquatable<OneOf<T1, T2, T3, T4>>

Type Parameters

T1

The first possible type.

T2

The second possible type.

T3

The third possible type.

T4

The fourth possible type.

Implements
IEquatable<OneOf<T1, T2, T3, T4>>
Inherited Members
Extension Methods

Remarks

OneOf<T1, T2, T3, T4> provides a type-safe way to represent a value that can be one of four types. This is useful for scenarios where you need to handle different types of values or states without using null references, exceptions, or complex enums.

Common use cases include: - API responses with four states: Success, ValidationError, NotFoundError, ServerError - Configuration values: String, Integer, Boolean, Double - Database operations: Created, Updated, Deleted, Conflict - File operations: Read, Write, Delete, Archive results

// API response handling
OneOf<SuccessData, ValidationError, NotFoundError, ServerError> response = await CallApi();
return response.Match(
    case1: data => ProcessData(data),
    case2: validationError => HandleValidationError(validationError),
    case3: notFoundError => HandleNotFoundError(notFoundError),
    case4: serverError => HandleServerError(serverError)
);

// Configuration parsing OneOf<string, int, bool, double> config = ParseConfigValue("timeout"); var processed = config.Match( case1: text => $"String: {text.ToUpper()}", case2: number => $"Number: {number * 2}", case3: flag => $"Boolean: {flag}", case4: decimal => $"Double: {decimal:F2}" );

Properties

AsT1

Gets the value as T1 if it contains T1, otherwise throws InvalidOperationException.

public T1 AsT1 { get; }

Property Value

T1

Exceptions

InvalidOperationException

Thrown when the OneOf contains T2, T3, or T4.

AsT2

Gets the value as T2 if it contains T2, otherwise throws InvalidOperationException.

public T2 AsT2 { get; }

Property Value

T2

Exceptions

InvalidOperationException

Thrown when the OneOf contains T1, T3, or T4.

AsT3

Gets the value as T3 if it contains T3, otherwise throws InvalidOperationException.

public T3 AsT3 { get; }

Property Value

T3

Exceptions

InvalidOperationException

Thrown when the OneOf contains T1, T2, or T4.

AsT4

Gets the value as T4 if it contains T4, otherwise throws InvalidOperationException.

public T4 AsT4 { get; }

Property Value

T4

Exceptions

InvalidOperationException

Thrown when the OneOf contains T1, T2, or T3.

IsT1

Gets whether the OneOf contains a value of type T1.

public bool IsT1 { get; }

Property Value

bool

IsT2

Gets whether the OneOf contains a value of type T2.

public bool IsT2 { get; }

Property Value

bool

IsT3

Gets whether the OneOf contains a value of type T3.

public bool IsT3 { get; }

Property Value

bool

IsT4

Gets whether the OneOf contains a value of type T4.

public bool IsT4 { get; }

Property Value

bool

Methods

BindT2<TNewT2>(Func<T2, OneOf<T1, TNewT2, T3, T4>>)

Binds the T2 value if present, otherwise propagates other types.

public OneOf<T1, TNewT2, T3, T4> BindT2<TNewT2>(Func<T2, OneOf<T1, TNewT2, T3, T4>> binder)

Parameters

binder Func<T2, OneOf<T1, TNewT2, T3, T4>>

The function that takes T2 and returns a OneOf.

Returns

OneOf<T1, TNewT2, T3, T4>

The result of the binder function or the original T1/T3/T4.

Type Parameters

TNewT2

The new T2 type.

Examples

OneOf<Error, Success, Warning, Info> result = GetInitialResult();
OneOf<Error, ProcessedData, Warning, Info> final = result.BindT2(success => ProcessSuccess(success));

Remarks

BindT2 (also known as flatMap or chain) allows you to chain operations that return OneOf. This is useful for sequential operations where each step might return a different type.

Exceptions

ArgumentNullException

Thrown when binder is null.

BindT3<TNewT3>(Func<T3, OneOf<T1, T2, TNewT3, T4>>)

Binds the T3 value if present, otherwise propagates other types.

public OneOf<T1, T2, TNewT3, T4> BindT3<TNewT3>(Func<T3, OneOf<T1, T2, TNewT3, T4>> binder)

Parameters

binder Func<T3, OneOf<T1, T2, TNewT3, T4>>

The function that takes T3 and returns a OneOf.

Returns

OneOf<T1, T2, TNewT3, T4>

The result of the binder function or the original T1/T2/T4.

Type Parameters

TNewT3

The new T3 type.

Examples

OneOf<Error, Success, Warning, Info> result = GetInitialResult();
OneOf<Error, Success, ProcessedWarning, Info> final = result.BindT3(warning => HandleWarning(warning));

Remarks

BindT3 (also known as flatMap or chain) allows you to chain operations that return OneOf. This is useful for sequential operations where each step might return a different type.

Exceptions

ArgumentNullException

Thrown when binder is null.

Equals(OneOf<T1, T2, T3, T4>)

Indicates whether the current OneOf is equal to another OneOf of the same type.

public bool Equals(OneOf<T1, T2, T3, T4> other)

Parameters

other OneOf<T1, T2, T3, T4>

The other OneOf to compare with.

Returns

bool

true if the OneOf instances are equal; otherwise, false.

Equals(object?)

Indicates whether the current OneOf is equal to another object.

public override bool Equals(object? obj)

Parameters

obj object

The object to compare with.

Returns

bool

true if the objects are equal; otherwise, false.

FromT1(T1)

Creates a OneOf containing a T1 value.

public static OneOf<T1, T2, T3, T4> FromT1(T1 value)

Parameters

value T1

The T1 value to wrap.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the specified T1 value.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = OneOf<Error, ValidationError, NotFoundError, Success>.FromT1(new NotFoundError());

FromT2(T2)

Creates a OneOf containing a T2 value.

public static OneOf<T1, T2, T3, T4> FromT2(T2 value)

Parameters

value T2

The T2 value to wrap.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the specified T2 value.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = OneOf<Error, ValidationError, NotFoundError, Success>.FromT2(new ValidationError("Invalid input"));

FromT3(T3)

Creates a OneOf containing a T3 value.

public static OneOf<T1, T2, T3, T4> FromT3(T3 value)

Parameters

value T3

The T3 value to wrap.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the specified T3 value.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = OneOf<Error, ValidationError, NotFoundError, Success>.FromT3(new NotFoundError("Resource not found"));

FromT4(T4)

Creates a OneOf containing a T4 value.

public static OneOf<T1, T2, T3, T4> FromT4(T4 value)

Parameters

value T4

The T4 value to wrap.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the specified T4 value.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = OneOf<Error, ValidationError, NotFoundError, Success>.FromT4(new Success("Operation completed"));

GetHashCode()

Returns the hash code for the OneOf.

public override int GetHashCode()

Returns

int

The hash code.

MapT2<TNewT2>(Func<T2, TNewT2>)

Maps the T2 value if present, otherwise propagates other types.

public OneOf<T1, TNewT2, T3, T4> MapT2<TNewT2>(Func<T2, TNewT2> mapper)

Parameters

mapper Func<T2, TNewT2>

The function to apply to the T2 value.

Returns

OneOf<T1, TNewT2, T3, T4>

A new OneOf with the mapped T2 value or the original T1/T3/T4.

Type Parameters

TNewT2

The new T2 type.

Examples

OneOf<Error, Success, Warning, Info> result = ProcessData();
OneOf<Error, ProcessedSuccess, Warning, Info> processed = result.MapT2(s => s.WithTimestamp());

Remarks

MapT2 allows you to transform the T2 value without unwrapping the OneOf. If the OneOf contains T1, T3, or T4, the mapper function is not called and those values are propagated.

Exceptions

ArgumentNullException

Thrown when mapper is null.

MapT3<TNewT3>(Func<T3, TNewT3>)

Maps the T3 value if present, otherwise propagates other types.

public OneOf<T1, T2, TNewT3, T4> MapT3<TNewT3>(Func<T3, TNewT3> mapper)

Parameters

mapper Func<T3, TNewT3>

The function to apply to the T3 value.

Returns

OneOf<T1, T2, TNewT3, T4>

A new OneOf with the mapped T3 value or the original T1/T2/T4.

Type Parameters

TNewT3

The new T3 type.

Examples

OneOf<Error, Success, Warning, Info> result = ProcessData();
OneOf<Error, Success, ProcessedWarning, Info> processed = result.MapT3(w => w.WithSeverity("High"));

Remarks

MapT3 allows you to transform the T3 value without unwrapping the OneOf. If the OneOf contains T1, T2, or T4, the mapper function is not called and those values are propagated.

Exceptions

ArgumentNullException

Thrown when mapper is null.

Match<TResult>(Func<T1, TResult>, Func<T2, TResult>, Func<T3, TResult>, Func<T4, TResult>)

Pattern matching - executes the appropriate function based on the contained type.

public TResult Match<TResult>(Func<T1, TResult> case1, Func<T2, TResult> case2, Func<T3, TResult> case3, Func<T4, TResult> case4)

Parameters

case1 Func<T1, TResult>

The function to execute when the OneOf contains T1.

case2 Func<T2, TResult>

The function to execute when the OneOf contains T2.

case3 Func<T3, TResult>

The function to execute when the OneOf contains T3.

case4 Func<T4, TResult>

The function to execute when the OneOf contains T4.

Returns

TResult

The result of the executed function.

Type Parameters

TResult

The type of the result.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = ProcessData();
string message = result.Match(
    case1: error => $"Error: {error.Message}",
    case2: validationError => $"Validation Error: {validationError.Message}",
    case3: notFoundError => $"Not Found: {notFoundError.Message}",
    case4: success => $"Success: {success.Message}"
);

Remarks

Match provides a type-safe way to handle all four possible cases without casting. This is similar to pattern matching in functional languages.

Exceptions

ArgumentNullException

Thrown when any case function is null.

Switch(Action<T1>, Action<T2>, Action<T3>, Action<T4>)

Executes an action based on the contained type.

public void Switch(Action<T1> case1, Action<T2> case2, Action<T3> case3, Action<T4> case4)

Parameters

case1 Action<T1>

The action to execute when the OneOf contains T1.

case2 Action<T2>

The action to execute when the OneOf contains T2.

case3 Action<T3>

The action to execute when the OneOf contains T3.

case4 Action<T4>

The action to execute when the OneOf contains T4.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = ProcessData();
result.Switch(
    case1: error => Console.WriteLine($"Error: {error.Message}"),
    case2: validationError => Console.WriteLine($"Validation Error: {validationError.Message}"),
    case3: notFoundError => Console.WriteLine($"Not Found: {notFoundError.Message}"),
    case4: success => Console.WriteLine($"Success: {success.Message}")
);

Remarks

Switch is useful for side effects when you don't need to return a value.

Exceptions

ArgumentNullException

Thrown when any case action is null.

ToString()

Converts to string for debugging.

public override string ToString()

Returns

string

A string representation of the OneOf.

Examples

OneOf<Error, Success, Warning> result = new Success("Data processed");
Console.WriteLine(result.ToString()); // "OneOf<T1, T2, T3>(T2: Success { Message = Data processed })"

Remarks

Returns the string representation of the contained value with type information. This is primarily useful for debugging and logging.

Operators

operator ==(OneOf<T1, T2, T3, T4>, OneOf<T1, T2, T3, T4>)

Determines whether two OneOf instances are equal.

public static bool operator ==(OneOf<T1, T2, T3, T4> left, OneOf<T1, T2, T3, T4> right)

Parameters

left OneOf<T1, T2, T3, T4>

The left OneOf to compare.

right OneOf<T1, T2, T3, T4>

The right OneOf to compare.

Returns

bool

true if the OneOf instances are equal; otherwise, false.

implicit operator OneOf<T1, T2, T3, T4>(T1)

Implicit conversion from T1 to OneOf<T1, T2, T3, T4>.

public static implicit operator OneOf<T1, T2, T3, T4>(T1 value)

Parameters

value T1

The T1 value to convert.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the T1 value.

implicit operator OneOf<T1, T2, T3, T4>(T2)

Implicit conversion from T2 to OneOf<T1, T2, T3, T4>.

public static implicit operator OneOf<T1, T2, T3, T4>(T2 value)

Parameters

value T2

The T2 value to convert.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the T2 value.

implicit operator OneOf<T1, T2, T3, T4>(T3)

Implicit conversion from T3 to OneOf<T1, T2, T3, T4>.

public static implicit operator OneOf<T1, T2, T3, T4>(T3 value)

Parameters

value T3

The T3 value to convert.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the T3 value.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = new NotFoundError("Resource not found"); // Implicit conversion

implicit operator OneOf<T1, T2, T3, T4>(T4)

Implicit conversion from T4 to OneOf<T1, T2, T3, T4>.

public static implicit operator OneOf<T1, T2, T3, T4>(T4 value)

Parameters

value T4

The T4 value to convert.

Returns

OneOf<T1, T2, T3, T4>

A OneOf containing the T4 value.

Examples

OneOf<Error, ValidationError, NotFoundError, Success> result = new Success("Operation completed"); // Implicit conversion

operator !=(OneOf<T1, T2, T3, T4>, OneOf<T1, T2, T3, T4>)

Determines whether two OneOf instances are not equal.

public static bool operator !=(OneOf<T1, T2, T3, T4> left, OneOf<T1, T2, T3, T4> right)

Parameters

left OneOf<T1, T2, T3, T4>

The left OneOf to compare.

right OneOf<T1, T2, T3, T4>

The right OneOf to compare.

Returns

bool

true if the OneOf instances are not equal; otherwise, false.