Result<T, E> API Reference

Complete API documentation for the `Result<T, E>` type and its extensions.

Result<T, E> Structure

1public readonly struct Result<T, E>
2{
3    public bool IsSuccess { get; }
4    public bool IsFailure { get; }
5    public T Value { get; }
6    public E Error { get; }
7}

Factory Methods

Success

Creates a successful result with a value.

1public static Result<T, E> Success(T value)
2
3// Example
4var result = Result<int, string>.Success(42);

Failure

Creates a failed result with an error.

1public static Result<T, E> Failure(E error)
2
3// Example
4var result = Result<int, string>.Failure("Not found");

Implicit Conversions

1// From value (success)
2Result<int, string> result = 42;
3
4// From error (failure)
5Result<int, string> result = "Error message";

Static Factory Methods

SuccessIf

Creates success if condition is true, otherwise failure.

1public static Result<T, E> SuccessIf(bool condition, T value, E error)
2public static Result<T, E> SuccessIf(Func<bool> condition, T value, E error)
3
4// Example
5var result = Result.SuccessIf(age >= 18, age, "Too young");

FailureIf

Creates failure if condition is true, otherwise success.

1public static Result<T, E> FailureIf(bool condition, T value, E error)
2public static Result<T, E> FailureIf(Func<bool> condition, T value, E error)
3
4// Example
5var result = Result.FailureIf(string.IsNullOrEmpty(name), name, "Name required");

Of

Wraps exception-throwing code into Result.

1public static Result<T, E> Of<T, E>(Func<T> func, Func<Exception, E> errorFactory)
2
3// Example
4var result = Result.Of(
5    () => int.Parse(input),
6    ex => $"Invalid number: {ex.Message}"
7);

Combine

Combines multiple Results into one (no value).

1// 2-5 parameters
2public static Result<Unit, E> Combine<E>(params Result<Unit, E>[] results)
3
4// Example
5var combined = Result.Combine(result1, result2, result3);

CombineValues

Combines multiple Results preserving values.

1// 2 parameters → tuple
2public static Result<(T1, T2), E> CombineValues<T1, T2, E>(
3    Result<T1, E> result1, 
4    Result<T2, E> result2)
5
6// 3-5 parameters → tuple
7public static Result<(T1, T2, T3), E> CombineValues<T1, T2, T3, E>(...)
8
9// Array → array
10public static Result<T[], E> CombineValues<T, E>(params Result<T, E>[] results)
11
12// Example
13var combined = Result.CombineValues(loadName, loadAge, loadEmail);
14// Returns: Result<(string, int, string), Error>

Transformation Methods

Map

Transforms success value.

1public Result<TNew, E> Map<TNew>(Func<T, TNew> mapper)
2
3// Example
4Result<int, string> age = 25;
5Result<string, string> category = age.Map(a => a >= 18 ? "Adult" : "Minor");

MapError

Transforms error value.

1public Result<T, ENew> MapError<ENew>(Func<E, ENew> errorMapper)
2
3// Example
4Result<int, string> result = "Not found";
5Result<int, ErrorDto> dto = result.MapError(e => new ErrorDto { Message = e });

MapSafe

Map with exception handling.

1public Result<TNew, E> MapSafe<TNew>(
2    Func<T, TNew> mapper, 
3    Func<Exception, E> errorHandler)
4
5// Example
6result.MapSafe(
7    data => ProcessData(data),  // Might throw
8    ex => $"Processing failed: {ex.Message}"
9);

Bind

Chains operations that return Result.

1public Result<TNew, E> Bind<TNew>(Func<T, Result<TNew, E>> binder)
2
3// Example
4Result<User, string> GetUser(int id) { }
5Result<Profile, string> GetProfile(User user) { }
6
7var profile = GetUser(123).Bind(user => GetProfile(user));

BindSafe

Bind with exception handling.

1public Result<TNew, E> BindSafe<TNew>(
2    Func<T, Result<TNew, E>> binder,
3    Func<Exception, E> errorHandler)

Validation Methods

Ensure

Adds validation predicate.

1public Result<T, E> Ensure(Func<T, bool> predicate, E error)
2public Result<T, E> Ensure(Func<T, bool> predicate, Func<T, E> errorFactory)
3
4// Example
5result
6    .Ensure(x => x > 0, "Must be positive")
7    .Ensure(x => x < 100, x => $"Value {x} is too large");

Side Effect Methods

Tap

Executes action on success without changing result.

1public Result<T, E> Tap(Action<T> onSuccess)
2public Result<T, E> Tap(Action<T> onSuccess, Action<E> onFailure)
3
4// Example
5result
6    .Tap(value => Debug.Log($"Success: {value}"))
7    .Tap(
8        onSuccess: value => SaveToCache(value),
9        onFailure: error => LogError(error)
10    );

TapSafe

Tap with exception handling.

1public Result<T, E> TapSafe(
2    Action<T> onSuccess,
3    Func<Exception, E> errorHandler)

Execute

Executes action and returns void.

1public void Execute(Action<T> onSuccess)
2public void Execute(Action<T> onSuccess, Action<E> onFailure)
3
4// Example
5result.Execute(
6    onSuccess: value => UpdateUI(value),
7    onFailure: error => ShowError(error)
8);

Pattern Matching

Match

Transforms Result to single value.

1public TResult Match<TResult>(
2    Func<T, TResult> onSuccess,
3    Func<E, TResult> onFailure)
4
5// Example
6string message = result.Match(
7    onSuccess: value => $"Success: {value}",
8    onFailure: error => $"Error: {error}"
9);

Finally

Terminal operation with Result access.

1public TResult Finally<TResult>(Func<Result<T, E>, TResult> finalizer)
2
3// Example
4var outcome = result.Finally(r => 
5{
6    LogResult(r);
7    return r.IsSuccess ? "OK" : "Failed";
8});

Error Recovery

OrElse

Provides alternative Result on failure.

1public Result<T, E> OrElse(Func<Result<T, E>> fallback)
2
3// Example
4var result = LoadFromCache()
5    .OrElse(() => LoadFromDisk())
6    .OrElse(() => LoadFromNetwork());

Or

Provides default value on failure.

1public T Or(T defaultValue)
2public T Or(Func<T> defaultFactory)
3
4// Example
5var value = LoadConfig().Or(new DefaultConfig());

Extraction Methods

TryGet

Attempts to get value/error with out parameters.

1public bool TryGetValue(out T value)
2public bool TryGetError(out E error)
3
4// Example
5if (result.TryGetValue(out var value))
6{
7    Process(value);
8}

GetValueOrThrow

Gets value or throws exception.

1public T GetValueOrThrow()
2public T GetValueOrThrow(string errorMessage)
3
4// Example
5var value = result.GetValueOrThrow("Operation failed");

Async Extensions (with NOPE_UNITASK)

Async Creation

1public static async UniTask<Result<T, E>> Of<T, E>(
2    Func<UniTask<T>> asyncFunc,
3    Func<Exception, E> errorFactory)
4
5// Example
6var result = await Result.Of(
7    async () => await FetchDataAsync(),
8    ex => $"Fetch failed: {ex.Message}"
9);

Map (Async)

Async transformation using the same method name.

1// Sync result → async transform
2public async UniTask<Result<TNew, E>> Map<TNew>(
3    Func<T, UniTask<TNew>> asyncMapper)
4
5// Async result → async transform  
6public static async UniTask<Result<TNew, E>> Map<T, TNew, E>(
7    this UniTask<Result<T, E>> resultTask,
8    Func<T, UniTask<TNew>> asyncMapper)
9
10// Example
11var result = await LoadData()
12    .Map(async data => await ProcessAsync(data));

Bind (Async)

Async chaining using the same method name.

1// Sync result → async binder
2public async UniTask<Result<TNew, E>> Bind<TNew>(
3    Func<T, UniTask<Result<TNew, E>>> asyncBinder)
4
5// Async result → async binder
6public static async UniTask<Result<TNew, E>> Bind<T, TNew, E>(
7    this UniTask<Result<T, E>> resultTask,
8    Func<T, UniTask<Result<TNew, E>>> asyncBinder)
9
10// Example
11var result = await ValidateInput(input)
12    .Bind(async valid => await SaveAsync(valid));

Tap (Async)

Async side effects using the same method name.

1public async UniTask<Result<T, E>> Tap(
2    Func<T, UniTask> onSuccessAsync)
3
4public async UniTask<Result<T, E>> Tap(
5    Func<T, UniTask> onSuccessAsync,
6    Func<E, UniTask> onFailureAsync)

Ensure (Async)

Async validation using the same method name.

1public async UniTask<Result<T, E>> Ensure(
2    Func<T, UniTask<bool>> asyncPredicate,
3    E error)

Extension Methods

EnableDebug (PRO feature)

1public DebugResult<T, E> EnableDebug(string flowName)
2
3// Example
4var result = LoadData()
5    .EnableDebug("DataLoad")
6    .Bind(ProcessData);

Complete Example

1public class UserService
2{
3    public async UniTask<Result<UserDto, ApiError>> GetUserAsync(string userId)
4    {
5        return await Result.SuccessIf(
6                !string.IsNullOrEmpty(userId), 
7                userId, 
8                new ApiError(400, "Invalid user ID"))
9            .EnableDebug($"GetUser_{userId}")
10            .Bind(id => FetchUserFromApiAsync(id))
11            .Ensure(
12                user => ValidateUserAsync(user), 
13                new ApiError(403, "User validation failed"))
14            .Map(user => EnrichUserDataAsync(user))
15            .Map(user => new UserDto
16            {
17                Id = user.Id,
18                Name = user.FullName,
19                Email = user.Email
20            })
21            .Tap(dto => CacheUserAsync(dto))
22            .MapError(error => 
23            {
24                LogError(error);
25                return new ApiError(500, "Internal error", error);
26            });
27    }
28}