Show / Hide Table of Contents

Result Type

Result<T> is similar to std::result data type in Rust programming language and allows to handle method call errors without try-catch block. The value can contain actual result returned from method or error in the form of exception.

.NET library provides TryInvoke extension methods to return Result<T> from popular delegate types such as Func, Converter. The type behaves like monad and the pipeline of calls can be constructed.

using DotNext;

Func<string, int> parser = int.Parse;
Result<int> result = parser.TryInvoke("42");
if (result)  //successful
{
    var i = (int)result;
}

Value property can be used to extract the value of the result, or throws the exception if the result is not available.

using DotNext;

Func<string, int> parser = int.Parse;
Result<int> result = parser.TryInvoke("42");
int value = result.Value; // may throw

Error property can be used to inspect the underlying exception:

using DotNext;

Func<string, int> parser = int.Parse;
Result<int> result = parser.TryInvoke("42");
if (result.IsSuccessful)  //successful
{
    var i = result.ValueOrDefault;
}
else
{
    Exception e = result.Error;
}
Note

It's not recommended to rethrow the exception by using Error property. It that case, you lose the information about initial stack trace. If you need to capture the state of the exception or rethrow it, use ExceptionDispatchInfo class.

Result type is paired with Optional data type. Result<T> can be converted to it implicitly. But conversion loses information about exception:

using DotNext;

Func<string, int> parser = int.Parse;
Optional<int> result = parser.TryInvoke("42");

Custom error codes

Result<T, TError> is an overloaded type that allows to use custom error codes instead of exceptions. The second generic parameter expects enum type that enumerates all possible error codes.

using DotNext;

enum ErrorCode
{
    Success = 0,
    InvalidInputString,
}

static Result<int, ErrorCode> TryParse(string input) => int.TryParse(input) ? input : new(ErrorCode.InvalidInputString);

Both types are interoperable:

Result<int, ErrorCode> result1 = TryParse("123");
Result<int> result2 = result1;
  • Edit this page
☀
☾
In this article
Back to top
Supported by the .NET Foundation
☀
☾