NetResults 1.0.0
dotnet add package NetResults --version 1.0.0
NuGet\Install-Package NetResults -Version 1.0.0
<PackageReference Include="NetResults" Version="1.0.0" />
<PackageVersion Include="NetResults" Version="1.0.0" />
<PackageReference Include="NetResults" />
paket add NetResults --version 1.0.0
#r "nuget: NetResults, 1.0.0"
#:package NetResults@1.0.0
#addin nuget:?package=NetResults&version=1.0.0
#tool nuget:?package=NetResults&version=1.0.0
NetResult
A simple and straightforward result type for C#. Inspired by Result type in language like F#, Rust, and Swift.
Creation
Result
types are created using static methods Result.Ok()
and Result.Error()
with provided success and error types.
// A Successful Result
var success = Result.Ok<MyObject, string>(new MyObject());
// An Error Result
var error = Result.Error<MyObject, string>("An error occurred. ");
When returning results, the types are inferred and can the static methods can omitted.
public Result<int, string> ErrorIfOverTen(int a)
{
if (a > 10)
return "An error occurred. 'a' was greater than 10. ";
else
return a;
}
Accessing Results
Results are built to be accessed in various ways. Safe ways include:
Pattern matching:
var res = ErrorIfOverTen(4);
switch (res)
{
case Ok<int, string> ok:
Console.WriteLine("Successful Result:" + ok);
// Note that 'ok' and 'err' values are implicitly read as their underlying unboxed values.
// Therefore the following is valid:
return ok + 4;
case Error<int, string> err:
Console.WriteLine("Error occured: " + err);
return 0;
}
the OnSuccess()
method performs some function on the value if it is a successful result.
var res = ErrorIfOverTen(20);
res.OnSuccess(
ok => Console.WriteLine("Success: " + ok)
);
the OnError()
method performs some function if the value is unsuccessful:
var res = ErrorIfOverTen(6);
res.OnError(
err => Console.WriteLine("An error occurred: " + err)
);
Both OnSuccess
and OnError
return the original result, so they can chained together:
var res = ErrorIfOverTen(9);
res.OnSuccess(ok => Console.WriteLine("Success: " + ok))
.OnError(err => Console.WriteLine("An error occurred: " + err));
If a valid value needs returned regardless of the result, Match()
can be used
var res = ErrorIfOverTen(20);
// Note that both methods must return the same type
var newNumber = res.Match(
ok => ok + 4 * 3, // on success
err => 0 // on error
)
The following ways of accessing the results are unsafe, so should be used with caution.
Guard methods:
var res = ErrorIfOverTen(13);
// if the result is a success, 'err' will be 'default(string)' in this scenario
if (res.IsError(out string err))
{
Console.WriteLine(err);
return;
}
// if the reuslt is an error, 'ok' will be 'default(int)' in this scenario
if (res.IsOk(out int ok))
{
DoSomethingWithNumber(ok);
return;
}
// These two methods can be combined into
if (res.IsError(out var ok, out var err))
{
Console.WriteLine(err);
return;
}
// Use the result since we know it'll have a value.
DoSomethingWithNumber(ok);
// Note: the inverse of `res.IsError(out var ok, out var err)` exists as `res.IsOk(out var ok, out var err)`
the Except
method can be used to force unwrap a result at the risk of throwing an UnwrappedResultException
if the result is an error. This method can be given an optional Exception
object to be the inner exception of the UnwrappedResultException
var res = ErrorIfOverTen(-3);
// Throws UnwrappedResultException
var forcedInteger = res.Except();
// Throw UnwrappedResultException with custom inner exception
var myException = new MyCustomException("My Exception's message");
forcedInteger = res.Except(myException);
Binding and Mapping
Results have methods Bind()
, Map()
, and BindError()
for safely performing operations on results.
Map does not affect the error value if it exits, and it will be propogated up:
var res = ErrorIfOverTen(3);
var newRes = res.Map(x => x * 2);
newRes.OnSuccess(ConsoleWriteLine); // Prints "6"
res = ErrorIfOverTen(13);
newRes = res.Map(x => x + 3);
newRes.OnError(Console.WriteLine); // Prints "An error occurred. 'a' was greater than 10. "
Bind also does not affect the error, but is used to to bind the result to a new result
var res = ErrorIfOverTen(6);
var newRes = res.Map(x => x * 2) // The result is now 12
.Bind(ErrorIfOverTen) // The result is now an error
Combining with Exceptions
The Result
class has a static Try()
method for mapping some operation than can throw into a result type
public void FunctionThatCanThrow()
{
// Perform operation that can throw exception
}
public void HandleMyException(Exception e)
{
// Handle the exception
}
Result.Try(
() => FunctionThatCanThrow(),
e => HandleMyException(e)
);
// Or shorthand
Result.Try(FunctionThatCanThrow, HandholeMyException);
Try()
can also return values if needed, however both the throwable function and the exception handler must return the same type
Result types themselves also have a Try()
method that can be called on them to attempt to perform a throwable operation on the result itself. Like the static function, these methods can also return a value.
var res = ErrorIfOverTen(14);
res.Try(
ok => FunctionThatCanThrow(ok),
e => Console.WriteLine(e)
)
Asynchronous Results
All mentioned methods have Async
version to deal with asynchronous operations
public async Task<Result<MyObject, string>> LongOperationAysnc(int input)
{
// perform async operation
if (thereWasAnError)
return "Oops, an error occurred. ";
else
return new MyObject();
}
Result<MyObject, string> res = await ErrorIfOverTen(3)
.BindAsync(LongOperationAsync)
.OnSuccessAsync(myObj => DoSomethingWith(myObj))
.OnErrorAsync(err => Console.WriteLine(err));
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
1.0.0 | 452 | 12/5/2020 |