QDev.CSharp.LanguageExtensions.Results 1.0.1

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

// Install QDev.CSharp.LanguageExtensions.Results as a Cake Tool
#tool nuget:?package=QDev.CSharp.LanguageExtensions.Results&version=1.0.1

Class Result<T, E>

Result<T, E> is a generic class that encapsulates either a successful result of type T or an error result of type E. It is commonly used to handle outcomes in a more structured and functional way, ensuring that both success and error cases are explicitly represented. This class provides methods for functional result handling, allowing developers to work with results in a functional and expressive manner, whether they are in the "Ok" or "Error" state. It offers a range of operations for transforming, chaining, and inspecting results, making it a powerful tool for result-based logic in applications. It is essential to handle exceptions appropriately, especially when using unwrapping methods, to ensure robust error handling.

This documentation includes extension methods that introduce functional programming features to this class.

Table of Contents

Installation

Using the NuGet package manager console within Visual Studio run the following command:

Install-Package QDev.CSharp.LanguageExtensions.Results

Or using the .NET Core CLI from a terminal window:

dotnet add package QDev.CSharp.LanguageExtensions.Results

Internal Methods

Constructors

This class provides two static constructors for creating instances of successful results (Ok) and error results (Err).

  • Result<T, E>.Ok(T value): Creates a new instance representing a successful result with the provided value.
  • Result<T, E>.Err(E error): Creates a new instance representing an error result with the provided error value or message.
Creating Results
// Creating a successful result
Result<int, string> successResult = Result<int, string>.Ok(42);

// Creating an error result
Result<int, string> errorResult = Result<int, string>.Err("Error message");

// Creating an error result as exception
Result<int, ArgumentException> errorResultException = Result<int, ArgumentException>.Err(new ArgumentException("Error message"));

Getters

  • Ok(): Retrieve the successful value if the result is successful; otherwise, returns null.
  • Err(): Retrieve the error value or message if the result is an error; otherwise, returns null.
  • IsOk: Gets a value indicating whether the result is successful.
  • IsErr: Gets a value indicating whether the result is an error.
Accessing Values

You can access the value of a result using the Ok() or Err() method. For better result handling, it is recommended to use the 'unwrapers' methods. These methods now throw exceptions in case of an error, and they require the programmer to handle these errors.

if (successResult.IsOk)
{
    int value = successResult.Ok()!.Value;
    // Use the successful value
}
else
{
    string error = successResult.Err()!;
    // Handle the error
}

Logic Operators

  • And<U>(Result<U, E> result): Combines this result with another result of a different type using a logical AND operation.
  • Or<F>(Result<T, F> result): Combines this result with another result of a different error type using a logical OR operation.
Examples of AND and OR operators

Both Results are Successful (Ok):

var resultA = Result<int, string>.Ok(42);
var resultB = Result<string, string>.Ok("Success");

var andResult = resultA.And(resultB); // Ok("Success")
var orResult = resultA.Or(resultB);   // Ok(42)

First Result is Successful (Ok), Second Result is an Error (Err):

var resultA = Result<int, string>.Ok(42);
var resultB = Result<string, string>.Err("Error Message");

var andResult = resultA.And(resultB); // Err("Error Message")
var orResult = resultA.Or(resultB);   // Ok(42)

First Result is an Error (Err), Second Result is Successful (Ok):

var resultA = Result<int, string>.Err("Error Message");
var resultB = Result<string, string>.Ok("Success");

var andResult = resultA.And(resultB); // Err("Error Message")
var orResult = resultA.Or(resultB);   // Ok("Success")

Both Results are Errors (Err):

var resultA = Result<int, string>.Err("Error 1");
var resultB = Result<string, string>.Err("Error 2");

var andResult = resultA.And(resultB); // Err("Error 1")
var orResult = resultA.Or(resultB);   // Err("Error 2")

Inspectors

  • Inspect(Action<T> inspector): Invokes an action on the value of the successful result.
  • InspectError(Action<E> inspector): Invokes an action on the error value or message of the error result.
Examples of Inspectors
// Inspect: Invokes an action on the value of the successful result if it's successful.
var result = Result<int, string>.Ok(42);
result.Inspect(value => Console.WriteLine($"Value is {value}"));
// Prints: Value is 42

// InspectError: Invokes an action on the error value or message if the result is an error.
result = Result<int, string>.Err("Error Message");
result.InspectError(error => Console.WriteLine($"Error occurred: {error}"));
// Prints: Error occurred: Error Message

Unwrappers

  • Expect(string message): Expects a successful result and returns its value; otherwise, throws an exception with the specified message.
  • Unwrap(): Returns the value of the successful result or throws an exception.
  • UnwrapOr(T defaultValue): Returns the value of the successful result or a defaultValue.
  • UnwrapOrDefault(): Returns the value of the successful result or default value for the type.
  • UnwrapUnchecked(): Returns the value of the successful result or throws an exception.
  • ExpectError(string message): Expects an error result and returns its error value; otherwise, throws an exception with the specified message.
  • UnwrapError(): Returns the error value of the error result or throws an exception.
  • UnwrapErrorUnchecked(): Returns the error value of the error result or throws an exception.
Examples of Unwrappers
// Methods for Successful Results
var resultOk = Result<int, string>.Ok(42);
var resultErr = Result<int, string>.Err("Error Message");

// Expect - Expects a successful result and returns its value
var valueOk = resultOk.Expect("Value was expected but not present"); // Returns 42
var valueErr = resultErr.Expect("Value was expected but not present"); // Throws an exception: "Value was expected but not present: Error Message"

// Unwrap - Returns the value of the successful result
// Throws an exception: "Error Message"
valueOk = resultOk.Unwrap(); // Returns 42
valueErr = resultErr.Unwrap(); // Throws an exception: "Error Message"

// UnwrapOrDefault - Returns the value of the successful result or default value for the type
valueOk = resultOk.UnwrapOrDefault(); // Returns 42
valueErr = resultErr.UnwrapOrDefault(); // Returns 0

// UnwrapUnchecked - Returns the value of the successful result or throws an exception
// Throws an UndefinedBehaviorException: "Undefined behavior for this result : {result}"
valueOk = resultOk.UnwrapUnchecked(); // Returns 42
valueErr = resultErr.UnwrapUnchecked(); // Throws an UndefinedBehaviorException: "Undefined behavior for this result : 42"

// Methods for Error Results

// ExpectError - Expects an error result and returns its error value
valueOk = resultOk.ExpectError("Error was expected but not present"); // Returns "Error was expected but not present: 42"
valueErr = resultErr.ExpectError("Error was expected"); // Returns "Error was expected: Error Message"

// UnwrapError - Returns the error value of the error result or throws an exception
// Throws an UnwrapException: "The value {value} could not be unwrapped: {message}"
valueOk = result.UnwrapError(); // Throws an UnwrapException: "The value "Error Message" could not be unwrapped: The result is not an error."
valueErr = result.UnwrapError(); // Returns "Error Message"

// UnwrapErrorUnchecked - Returns the error value of the error result or throws an exception
// Throws an UndefinedBehaviorException: "Undefined behavior for this result: {result}"
valueOk = resultOk.UnwrapErrorUnchecked(); // Throws an UndefinedBehaviorException: "Undefined behavior for this result: 42"
valueErr = resultErr.UnwrapErrorUnchecked(); // Returns "Error Message"

Functional Programming Features

Extensors Logic Operators

  • AndThen<U>(Func<T, Result<U, E>> function): Calls function if the result is successful; otherwise returns a new instance representing this error result.
  • OrElse<F>(Func<E, Result<T, F>> function): Calls function if the result is NOT successful; otherwise returns a new instance representing this ok result.

Extensors Mappers & Flattens

Mappers

  • Map<U>(Func<T, U> mapper): Maps the successful result value to a new value of a different type.
  • MapError<F>(Func<E, F> mapper): Maps the error value or message to a new value of a different type.
  • MapOr<U>(Func<T, U> mapper, U defaultValue): Maps the successful result value to a new value or returns a defaultValue.
  • MapOrElse<U>(Func<T, U> mapper, Func<E, U> function): Maps the successful result or returns a value based on the error object.

Flattens

  • Result<T, E> Flatten<T, E>(this Result<Result<T, E>, E> result): Flattens a nested result by extracting the inner result, discarding the error value of the outer result.
How mapping results
// Map: Map<U>(Func<T, U> mapper)
var result = Result<int, string>.Ok(42);
var mappedResult = result.Map(value => $"The answer is {value}");
// mappedResult is now Result<string, string>.Ok("The answer is 42")

// MapError: MapError<F>(Func<E, F> mapper)
result = Result<int, string>.Err("Error Message");
mappedResult = result.MapError(error => $"An error occurred: {error}");
// mappedResult is now Result<int, string>.Err("An error occurred: Error Message")

// MapOr: MapOr<U>(Func<T, U> mapper, U defaultValue)
result = Result<int, string>.Ok(42);
var mappedValueFromOk = result.MapOr(value => value * 2, defaultValue: 0);
// mappedValue is now 84

// MapOr: MapOr<U>(Func<T, U> mapper, U defaultValue)
result = Result<int, string>.Error("Error Message");
var mappedValueFromErr = result.MapOr(value => value * 2, defaultValue: 0);
// mappedValue is now 0

// MapOrElse: MapOrElse<U>(Func<T, U> mapper, Func<E, U> function)
result = Result<int, string>.Ok(42);
mappedValueFromErr = result.MapOrElse(value => value * 2, error => error.Length);
// mappedValue is now 84

// MapOrElse: MapOrElse<U>(Func<T, U> mapper, Func<E, U> function)
result = Result<int, string>.Err("Error Message");
mappedValueFromErr = result.MapOrElse(value => value * 2, error => error.Length);
// mappedValue is the length of the error message, which is 13
How Flattening results
// Creating a nested result
var nestedOkResult = Result<Result<int, string>, string>.Ok(Result<int, string>.Ok(42));
var nestedResult = Result<Result<int, string>, string>.Ok(Result<int, string>.Err("Error Message"));
var nestedErrResult = Result<Result<int, string>, string>.Err("Error Message");

// Flattening the nested result to get the inner result
var flattenedResult = nestedOkResult.Flatten(); // Ok(42)
flattenedResult = nestedResult.Flatten(); // Error("Error Message")
flattenedResult = nestedErrResult.Flatten(); // Error("Error Message")

Extensors Unwrappersl

  • UnwrapOrElse(Func<E, T> function): Returns the value of the successful result or a value based on the error object.
Examples of Unwrappers
// UnwrapOrElse - Returns the value of the successful result or a value based on the error object
valueOk = resultOk.UnwrapOrElse(error => error.Length); // Returns 42
valueErr = resultErr.UnwrapOrElse(error => error.Length); // Returns 13 (length of the error message)
Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net7.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.1 222 10/31/2023
1.0.0 96 10/30/2023

first release