Struct Result<TValue>
- Namespace
- Trellis
- Assembly
- Trellis.Core.dll
Represents either a successful computation (with a value) or a failure (with an Error).
public readonly struct Result<TValue> : IResult<TValue>, IResult, IEquatable<Result<TValue>>, IFailureFactory<Result<TValue>>
Type Parameters
TValueSuccess value type.
- Implements
-
IResult<TValue>IEquatable<Result<TValue>>IFailureFactory<Result<TValue>>
- Inherited Members
- Extension Methods
-
CheckIfExtensionsAsync.CheckIfAsync<T, TK>(Result<T>, Func<T, bool>, Func<T, ValueTask<Result<TK>>>)
Examples
// Creating results
Result<User> success = Result.Ok(user);
Result<User> failure = new Error.NotFound(new ResourceRef("User", "42")) { Detail = "User not found" };
// Pattern matching with Deconstruct
var (isSuccess, value, error) = result;
var message = isSuccess
? $"Found user: {value!.Name}"
: $"Error: {error!.Detail}";
// Or use the safe accessors
if (result.TryGetValue(out var user)) Console.WriteLine(user.Name);
else if (result.Error is { } err) Console.WriteLine(err.Detail);
// Chaining operations
var finalResult = GetUser(id)
.Bind(user => ValidateUser(user))
.Map(user => user.Name);
Remarks
Result is the core type for Railway Oriented Programming. It forces explicit handling of both success and failure cases, making error handling visible in the type system. Use Result when an operation can fail in a predictable way that should be handled by the caller.
default(Result<T>) represents a failure carrying a sentinel
Error.Unexpected with ReasonCode = "default_initialized". This makes
uninitialized state a typed failure rather than a silent success that would hide a programming error.
Always construct via Ok<TValue>(TValue) or Fail<TValue>(Error); analyzer
TRLS019 flags explicit default(Result<T>) at call sites.
Properties
Error
Gets the error when this result is a failure, or null when it is a success.
public Error? Error { get; }
Property Value
Examples
if (result.Error is { } error)
return error switch
{
Error.NotFound nf => HandleNotFound(nf),
_ => HandleGeneric(error),
};
Remarks
Reading this property never throws. The nullable return type is the discriminator: a non-null
Error means the result is a failure; null means success.
For default(Result<T>), returns the shared Error.Unexpected
sentinel so default-initialized failures are observationally equivalent to
Result.Fail<T>(new Error.Unexpected("default_initialized")).
IsFailure
True when the result represents failure.
[MemberNotNullWhen(true, "Error")]
public bool IsFailure { get; }
Property Value
- bool
True if failed; otherwise false.
Remarks
default(Result<T>).IsFailure is true.
IsSuccess
True when the result represents success.
[MemberNotNullWhen(false, "Error")]
public bool IsSuccess { get; }
Property Value
- bool
True if successful; otherwise false.
Methods
AsUnit()
Converts this Result<TValue> to a no-payload Result<TValue>, discarding the success value. Failures preserve their Error.
public Result<Unit> AsUnit()
Returns
- Result<Unit>
A Result<TValue> mirroring this result's success/failure state.
Remarks
Use AsUnit() when a pipeline returns a value but the next step only cares about success/failure
(e.g., bridging a value-producing operation into a no-payload consumer). This returns the canonical
no-payload result shape Result<Unit>. For default-initialized failures
the returned result is constructed via Fail(Error) with
the shared sentinel — never returns a default-initialized Result<Unit>.
CreateFailure(Error)
Creates a failure result wrapping the given error. Used by generic pipeline behaviors that need to construct failure results without knowing the inner type parameter.
public static Result<TValue> CreateFailure(Error error)
Parameters
errorErrorThe error describing the failure.
Returns
- Result<TValue>
A failed Result<TValue>.
Deconstruct(out bool, out TValue?, out Error?)
Deconstructs the result into its components for pattern matching.
public void Deconstruct(out bool isSuccess, out TValue? value, out Error? error)
Parameters
isSuccessboolTrue if the result is successful; otherwise false.
valueTValueThe success value if successful; otherwise default.
errorErrorThe error if failed; otherwise null.
Examples
var (success, value, error) = GetUser(id);
if (success)
Console.WriteLine($"User: {value!.Name}");
else
Console.WriteLine($"Error: {error!.Detail}");
Equals(object?)
Determines whether the specified object is equal to the current result.
public override bool Equals(object? obj)
Parameters
objobjectThe object to compare with the current result.
Returns
- bool
True if the specified object is a Result and is equal to the current result; otherwise false.
Equals(Result<TValue>)
Determines whether the specified result is equal to the current result.
public bool Equals(Result<TValue> other)
Parameters
otherResult<TValue>The result to compare with the current result.
Returns
- bool
True if the specified result is equal to the current result; otherwise false.
Remarks
Two results are equal if they have the same success/failure state and equal values/errors.
Default-initialized failures use the shared sentinel Error.Unexpected
so two default(Result<T>) values are equal, and a default
equals an explicit Result.Fail<T>(...) with the same sentinel.
GetHashCode()
Returns a hash code for the current result.
public override int GetHashCode()
Returns
- int
A hash code for the current result.
ToString()
Returns a string representation of the result.
public override string ToString()
Returns
- string
A string in the format "Success(value)" or "Failure(ErrorCode: detail)".
TryGetError(out Error?)
Attempts to get the error without throwing. Companion to Error for callers
that prefer TryParse-style imperative usage where a non-null local binding is desired.
public bool TryGetError(out Error? error)
Parameters
Returns
TryGetValue(out TValue)
Attempts to get the success value without throwing.
[MemberNotNullWhen(false, "Error")]
public bool TryGetValue(out TValue value)
Parameters
valueTValueWhen this method returns true, contains the success value; otherwise, the default value.
Returns
- bool
True if the result is successful; otherwise false.
Remarks
Equivalent to !IsFailure; provided as a TryParse-style convenience that binds the value in a single call.
TryGetValue(out TValue, out Error?)
Attempts to get the success value and the error in a single call, eliminating the need
for result.Error! null-suppression after a failed TryGetValue(out TValue).
public bool TryGetValue(out TValue value, out Error? error)
Parameters
valueTValueWhen this method returns true, contains the success value; otherwise, the default value.
errorErrorWhen this method returns false, contains the error; otherwise null.
Returns
Examples
if (!result.TryGetValue(out var v, out var err))
return Result.Fail<T>(err); // err is non-null here (flow-analysis verified)
// use v on success
Operators
operator ==(Result<TValue>, Result<TValue>)
Determines whether two results are equal.
public static bool operator ==(Result<TValue> left, Result<TValue> right)
Parameters
Returns
- bool
True if the results are equal; otherwise false.
operator !=(Result<TValue>, Result<TValue>)
Determines whether two results are not equal.
public static bool operator !=(Result<TValue> left, Result<TValue> right)
Parameters
Returns
- bool
True if the results are not equal; otherwise false.