Struct OneOf<T1, T2>
- Namespace
- REslava.Result.AdvancedPatterns
- Assembly
- REslava.Result.dll
Represents a value that can be one of two possible types. A type-safe discriminated union for functional programming patterns.
public readonly struct OneOf<T1, T2> : IEquatable<OneOf<T1, T2>>
Type Parameters
T1The first possible type.
T2The second possible type.
- Implements
-
IEquatable<OneOf<T1, T2>>
- Inherited Members
- Extension Methods
Remarks
OneOf<T1, T2> provides a type-safe way to represent a value that can be one of two types. This is useful for scenarios where you need to handle different types of values or errors without using null references or exceptions.
Common use cases include: - Error handling with typed errors: OneOf<Error, Success> - Configuration values: OneOf<string, int> - API responses: OneOf<ValidationError, Data>
// Error handling
OneOf<Error, User> user = GetUser(id);
return user.Match(
error => HandleError(error),
user => ProcessUser(user)
);
// Configuration parsing
OneOf<string, int> config = GetConfig("timeout");
int timeout = config.Match(
str => int.Parse(str),
num => num
);
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.
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.
IsT1
Gets whether the OneOf contains a value of type T1.
public bool IsT1 { get; }
Property Value
IsT2
Gets whether the OneOf contains a value of type T2.
public bool IsT2 { get; }
Property Value
Methods
Bind<TNewT2>(Func<T2, OneOf<T1, TNewT2>>)
Binds the T2 value if present, otherwise propagates T1.
public OneOf<T1, TNewT2> Bind<TNewT2>(Func<T2, OneOf<T1, TNewT2>> binder)
Parameters
Returns
- OneOf<T1, TNewT2>
The result of the binder function or the original T1.
Type Parameters
TNewT2The new T2 type.
Examples
OneOf<Error, int> userId = GetUserId();
OneOf<Error, User> user = userId.Bind(id => GetUser(id));
Remarks
Bind (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>)
Determines equality between two OneOf instances.
public bool Equals(OneOf<T1, T2> other)
Parameters
otherOneOf<T1, T2>The other OneOf to compare with.
Returns
- bool
true if the OneOf instances are equal; otherwise, false.
Equals(object?)
Determines equality between the OneOf and another object.
public override bool Equals(object? obj)
Parameters
objobjectThe object to compare with.
Returns
- bool
true if the objects are equal; otherwise, false.
Filter(Func<T2, bool>, T1)
Filters the T2 value if it satisfies the predicate, otherwise converts to T1.
public OneOf<T1, T2> Filter(Func<T2, bool> predicate, T1 fallbackT1)
Parameters
predicateFunc<T2, bool>The condition to test the T2 value against.
fallbackT1T1The T1 value to use when the predicate fails.
Returns
- OneOf<T1, T2>
The original OneOf if the predicate is true, otherwise the fallback T1.
Examples
OneOf<Error, User> user = GetUser(id);
OneOf<Error, User> activeUser = user.Filter(u => u.IsActive, new UserInactiveError());
Remarks
Filter allows you to conditionally keep or discard the T2 value. If the OneOf contains T1, the predicate is not evaluated and T1 is returned.
Exceptions
- ArgumentNullException
Thrown when predicate is null.
FromT1(T1)
Creates a OneOf containing a T1 value.
public static OneOf<T1, T2> FromT1(T1 value)
Parameters
valueT1The T1 value to wrap.
Returns
- OneOf<T1, T2>
A OneOf containing the specified T1 value.
Examples
OneOf<Error, User> result = OneOf<Error, User>.FromT1(new NotFoundError());
FromT2(T2)
Creates a OneOf containing a T2 value.
public static OneOf<T1, T2> FromT2(T2 value)
Parameters
valueT2The T2 value to wrap.
Returns
- OneOf<T1, T2>
A OneOf containing the specified T2 value.
Examples
OneOf<Error, User> result = OneOf<Error, User>.FromT2(new User("Alice"));
GetHashCode()
Returns the hash code for the OneOf.
public override int GetHashCode()
Returns
- int
The hash code.
Map<TNewT2>(Func<T2, TNewT2>)
Maps the T2 value if present, otherwise propagates T1.
public OneOf<T1, TNewT2> Map<TNewT2>(Func<T2, TNewT2> mapper)
Parameters
mapperFunc<T2, TNewT2>The function to apply to the T2 value.
Returns
- OneOf<T1, TNewT2>
A new OneOf with the mapped T2 value or the original T1.
Type Parameters
TNewT2The new T2 type.
Examples
OneOf<Error, User> user = GetUser(id);
OneOf<Error, string> userName = user.Map(u => u.Name);
Remarks
Map allows you to transform the T2 value without unwrapping the OneOf. If the OneOf contains T1, the mapper function is not called and T1 is propagated.
Exceptions
- ArgumentNullException
Thrown when mapper is null.
Match<TResult>(Func<T1, TResult>, Func<T2, TResult>)
Pattern matching - executes the appropriate function based on the contained type.
public TResult Match<TResult>(Func<T1, TResult> case1, Func<T2, TResult> case2)
Parameters
case1Func<T1, TResult>The function to execute when the OneOf contains T1.
case2Func<T2, TResult>The function to execute when the OneOf contains T2.
Returns
- TResult
The result of the executed function.
Type Parameters
TResultThe type of the result.
Examples
OneOf<Error, User> result = GetUser(id);
string message = result.Match(
error => $"Error: {error.Message}",
user => $"User: {user.Name}"
);
Remarks
Match provides a type-safe way to handle both possible cases without casting. This is similar to pattern matching in functional languages.
Exceptions
- ArgumentNullException
Thrown when case1 or case2 is null.
Switch(Action<T1>, Action<T2>)
Executes an action based on the contained type.
public void Switch(Action<T1> case1, Action<T2> case2)
Parameters
case1Action<T1>The action to execute when the OneOf contains T1.
case2Action<T2>The action to execute when the OneOf contains T2.
Examples
OneOf<Error, User> result = GetUser(id);
result.Switch(
error => Console.WriteLine($"Error: {error.Message}"),
user => Console.WriteLine($"User: {user.Name}")
);
Remarks
Switch is useful for side effects when you don't need to return a value.
Exceptions
- ArgumentNullException
Thrown when case1 or case2 is null.
ToString()
Converts to string for debugging.
public override string ToString()
Returns
- string
A string representation of the OneOf.
Examples
OneOf<Error, User> user = new User("Alice");
Console.WriteLine(user.ToString()); // "OneOf<T1, T2>(T2: User { Name = Alice })"
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>, OneOf<T1, T2>)
Equality operator for OneOf instances.
public static bool operator ==(OneOf<T1, T2> left, OneOf<T1, T2> right)
Parameters
Returns
- bool
true if the OneOf instances are equal; otherwise, false.
implicit operator OneOf<T1, T2>(T1)
Implicit conversion from T1 to OneOf<T1, T2>.
public static implicit operator OneOf<T1, T2>(T1 value)
Parameters
valueT1The T1 value to convert.
Returns
- OneOf<T1, T2>
A OneOf containing the T1 value.
Examples
OneOf<Error, User> result = new NotFoundError(); // Implicit conversion
implicit operator OneOf<T1, T2>(T2)
Implicit conversion from T2 to OneOf<T1, T2>.
public static implicit operator OneOf<T1, T2>(T2 value)
Parameters
valueT2The T2 value to convert.
Returns
- OneOf<T1, T2>
A OneOf containing the T2 value.
Examples
OneOf<Error, User> result = new User("Alice"); // Implicit conversion
operator !=(OneOf<T1, T2>, OneOf<T1, T2>)
Inequality operator for OneOf instances.
public static bool operator !=(OneOf<T1, T2> left, OneOf<T1, T2> right)
Parameters
Returns
- bool
true if the OneOf instances are not equal; otherwise, false.