Frostware.Result 1.0.0

dotnet add package Frostware.Result --version 1.0.0
NuGet\Install-Package Frostware.Result -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="Frostware.Result" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Frostware.Result --version 1.0.0
#r "nuget: Frostware.Result, 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.
// Install Frostware.Result as a Cake Addin
#addin nuget:?package=Frostware.Result&version=1.0.0

// Install Frostware.Result as a Cake Tool
#tool nuget:?package=Frostware.Result&version=1.0.0

Frostware.Result

nuget openupm

A simple implementation of a functional result type in C#

Table of contents

What is a result type, and why use it?

The result type is an alternative to a try/catch that aims to remove the need for nulls and force handling of failed cases.

By having your methods return Result, it allows you to pattern match (switch) over that result at execution. You can then supply an implementation for every possible state of your method.

How to use

This is the main result class:

public class Result
{
     // Pass inherits Result
     public static Result Pass() => new Pass(); 
     // Pass<T> inherits Pass
     public static Result Pass<T>(T value) => new Pass<T>(value); 
     
     //Fail inherits Result
     public static Result Fail(string errorMessage = "") => new Fail(errorMessage); 
     //Fail<T> inherits Fail
     public static Result Fail<T>(T value, string errorMessage = default) => new Fail<T>(value, errorMessage); 
}

A few things to note here:

  • Pass can either be empty or contain a value.
  • Pass<T> is a Pass, Pass is a Result. This distinction is important for pattern matching.
  • Fail works the same as Pass but has an added optional error message.

Method Decleration

Simply make your method return the type "Result" and use the static helper methods on the Result class.

/// <summary>
/// Example Method
/// </summary>
/// <returns>Pass : int, Fail : int, Fail : foo</returns>
public Result ExampleMethod()
{
     if (condition1)
         return Result.Pass(20); //returns Pass<int> { Value = 20 }
     else if (condition2)
         return Result.Pass(); //returns Pass {}
     else if (condition3)
         return Result.Fail(30, "Oporation Failed"); //returns Fail<Int> { Value = 30, ErrorMessage = "Oporation Failed" }
     else if (condition4)
         return Result.Fail(new Foo()); //returns Fail<Foo> { Value = Foo {}, ErrorMessage = "" }
     else
         return Result.Fail(); //returns Fail {ErrorMessage = ""}
}

You may of noticed that we are returning both a Fail<int> and a Fail<Foo>. You can do that! Since you should be handling all possible states of your result this won't be a problem at all. Just make sure your method's summery is clear about how it works and what it may return. See the <returns /> tag for an example

Result Handling

It is recomended to pattern match over the result, either with a switch statement,

switch(ExampleMethod())
{
     case Pass<int> x:
         //triggered when result is a pass and contains a value of int
         break;
 
     case Pass<Foo> x:
         //triggered when result is a pass and contains a value of Foo
         break;
 
     case Pass _: //you can ommit the "_" as of .NET 5
         //triggered when result is a pass of any type
         break;
 
 
     case Fail<int> x:
         //triggered when result is a fail and contains a value of int
         break;
 
     case Fail<Foo> x:
         //triggered when result is a fail and contains a value of Foo
         break;
 
     case Fail _: //you can ommit the "_" as of .NET 5
         //triggered when result is a fail of any type
         break;
}

or a switch expression.

string result = ExampleMethod() switch
{
     Pass<int> x => $"This is a pass that contains the int {x.Value}",
     Pass<Foo> x => $"This is a pass that contains an instance of the class Foo {x.Value}",
     Pass => "This is an empty pass",
 
     Fail<int> x => $"This failed with message {x.ErrorMessage} and contains the int {x.Value}",
     Fail<Foo> x => $"This failed with message {x.ErrorMessage} and contains an instance of the class foo {x.Value}",
     Fail x => $"This failed with message {x.ErrorMessage}"
}

Note that if you check for Pass before Pass<int> the compiler will throw an error stating that the pattern or case has already been handled. This is do to Pass<int> being a Pass. This is intentional, it means that if you just want to check if an oporation passed and don't care about the value, you can just check for Pass. Same applies to Fail.

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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  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.0

    • 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 309 2/19/2021