NetResults 1.0.0

dotnet add package NetResults --version 1.0.0
                    
NuGet\Install-Package NetResults -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NetResults" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NetResults" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="NetResults" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NetResults --version 1.0.0
                    
#r "nuget: NetResults, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NetResults@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NetResults&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=NetResults&version=1.0.0
                    
Install as a Cake Tool

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .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