An open API service indexing awesome lists of open source software.

https://github.com/skbkontur/results


https://github.com/skbkontur/results

csharp

Last synced: about 1 year ago
JSON representation

Awesome Lists containing this project

README

          

# Yet another `Result` types implementation

[![NuGet](https://img.shields.io/nuget/v/Kontur.Results.svg)](https://www.nuget.org/packages/Kontur.Results/)

This library consists of three `Result` types with some tempting [features](#features) :
* `Optional`
* `Result`
* `Result`

## Content

* [License](#license)
* [Installation](#installation)
* [Nuget](#nuget)
* [Cement](#cement)
* [Examples](#examples)
* [Features](#features)
* [Drawbacks](#drawbacks)
* [Instantiation of types](#instantiation-of-types)
* [Extraction of data from instances](#extraction-of-data-from-instances)
* [TryGetValue](#trygetvalue)
* [TryGetFault](#trygetfault)
* [Match](#match)
* [Switch](#switch)
* [OnSome](#onsome)
* [OnNone](#onnone)
* [OnSuccess](#onsuccess)
* [OnFailure](#onfailure)
* [Switch/OnSome/OnNone/OnSuccess/OnFailure method chaining](#switchonsomeonnoneonsuccessonfailure-method-chaining)
* [Switch/OnSome/OnNone/OnSuccess/OnFailure return value upcasting](#switchonsomeonnoneonsuccessonfailure-return-value-upcasting)
* [GetValueOrElse](#getvalueorelse)
* [GetFaultOrElse](#getfaultorelse)
* [GetValueOrThrow](#getvalueorthrow)
* [GetFaultOrThrow](#getfaultorthrow)
* [GetValueOrDefault](#getvalueordefault)
* [GetFaultOrDefault](#getfaultordefault)
* [GetValueOrNull](#getvalueornull)
* [GetFaultOrNull](#getfaultornull)
* [EnsureHasValue](#ensurehasvalue)
* [EnsureNone](#ensurenone)
* [EnsureSuccess](#ensuresuccess)
* [EnsureFailure](#ensurefailure)
* [HasSome](#hassome)
* [IsNone](#isnone)
* [Success](#success)
* [Failure](#failure)
* [LINQ method syntax (GetValues, GetFaults)](#linq-method-syntax-getvalues-getfaults)
* [LINQ query syntax](#linq-query-syntax)
* [foreach](#foreach)
* [ToString](#tostring)
* [Upcasts](#upcasts)
* [Conversion of generic arguments](#conversion-of-generic-arguments)
* [MapValue](#mapvalue)
* [MapFault](#mapfault)
* [Upcast](#upcast)
* [Result combining](#result-combining) or monadic extensions
* [Then](#then)
* [OrElse](#orelse)
* [Then/OrElse method chaining](#thenorelse-method-chaining)
* [Select](#select)
* [Do notation](#do-notation)
* [Do notation with async extensions](#do-notation-with-async-extensions)
* [Inheritance](#inheritance)
* [Other](#other)
* [Yet to be implemented](#yet-to-be-implemented)
* [Contributing](#contributing)

## License

MIT

## Installation

### Nuget

Execute that command in Package Manager console to install [Kontur.Results](https://www.nuget.org/packages/Kontur.Results/):

`Install-Package Kontur.Results -Version 1.0.1`

Execute the following command instead to install [Kontur.Results.Monad](https://www.nuget.org/packages/Kontur.Results.Monad/) if you are willing for [monadic extensions](#result-combining) (implemented separately). It consists of [Then](#then), [OrElse](#orelse), [Select](#select) and [do notation](#do-notation-with-async-extensions):

`Install-Package Kontur.Results.Monad -Version 1.0.1`

### Cement

Use [cement](https://github.com/skbkontur/cement#get-started) to add a reference to `Kontur.Results` assembly.

Execute that command in your cement module:

`cm ref add results your-csproj.csproj`

Execute the following command in your cement module instead if you are willing for [monadic extensions](#result-combining) (implemented separately). It consists of [Then](#then), [OrElse](#orelse), [Select](#select) and [do notation](#do-notation-with-async-extensions):

`cm ref add results/monad your-csproj.csproj`

## Examples

Checking Result status and extracting data with single method

```csharp
using Kontur.Results;

Result result = "success!"; // implicit conversion

if (result.TryGetValue(out string value, out var faultCode))
{
Console.WriteLine(value.ToString()) // OK. Value is not null here. The compiler allows this.
}

Console.WriteLine("Error code: " + faultCode);
Console.WriteLine(value.ToString()) // warning CS8602: Dereference of a possibly null reference.
```

Converting Result-way error handling to exception-way error handling

```csharp
using Kontur.Results;

class DraftError
{
public int Code { get; init; }
}

class DraftClient
{
...
public Task> CreateDraft()
{
...
}
}

Result createDraftResult = await new DraftClient().CreateDraft();
try
{
Draft draft = createDraftResult.GetValueOrThrow();
Console.WriteLine(draft.Id);
}
catch (ResultFailedException ex)
{
Console.WriteLine("Error code: " + ex.Fault.Code));
}
```

Working with values without extracting it from Result instances

```csharp
abstract Task> GetFormLogin();
abstract Optional GetUser(LoginModel login);
abstract ValueTask> CreateUser(LoginModel login);

Task> userId =
GetFormLogin()
.MapValue(str => new LoginModel(str))
.Then(login => GetUser(login).OrElse(() => CreateUser(login)))
```

Do notation reduces the count of checks and await operators significantly

```csharp
abstract ValueTask> GetCurrentUserId();
abstract Result EnsureUserIdIsCorrect(Guid userId);
abstract Task GetCurrentIndex();
abstract Task> GetMessage(Guid userId, int index);
abstract Result Convert(string message, Guid userId);

Task> result =
from userId in GetCurrentUserId()
where EnsureUserIdIsCorrect(userId)
from index in GetCurrentIndex()
let nextIndex = index + 1
from message in GetMessage(userId, nextIndex)
select Convert(message, userId);
```

Data parsing

```csharp
class NaturalNumber
{
private readonly int value;
private NaturalNumber(int value) => this.value = value;
public static NaturalNumber operator +(NaturalNumber a, NaturalNumber b) => new NaturalNumber(a.value + b.value);

public static bool TryParse(int value, [MaybeNullWhen(returnValue: false)] out NaturalNumber number)
{
if (value > 0)
{
number = new NaturalNumber(value);
return true;
}
number = null;
return false;
}

public static Optional TryParse(int value) => TryParse(value, out var number) ? number : Optional.None();
public static NaturalNumber Parse(int value) => TryParse(value).GetValueOrThrow();
}

Result TryParseString(string input) => int.TryParse(input, out var number)
? number
: new Exception(input + " is not an integer");

Result result =
from int1 in TryParseString(Console.ReadLine())
from natural1 in NaturalNumber.TryParse(int1).OrElse(Result.Fail(new Exception(int1 + " is not positive")))
from int2 in TryParseString(Console.ReadLine())
from natural2 in NaturalNumber.TryParse(int2).OrElse(Result.Fail(new Exception(int2 + " is not positive")))
select natural1 + natural2;
```

Inheritance to freeze fault type

```csharp
class StringFaultResult : Result
{
private readonly Result result;

public StringFaultResult(string fault) => result = fault;
public StringFaultResult(TValue value) => result = value;

public override TResult Match(Func onFailure, Func onSuccess)
=> result.Match(onFailure, onSuccess);
}

public StringFaultResult GenerateInt()
{
int randomValue = new Random().Next(0, 10);
if (randomValue > 0)
{
return new StringFaultResult(randomValue);
}

return new StringFaultResult("Failed to generate a positive number");
}
```

## Features

* [Do notation](#do-notation-with-async-extensions) with support of async (`Task` and `ValueTask`) execution and without limit on the expression count.
* [Then](#then) (`And`, `ContinueWith`, `ContinueOnSome`, `Bind`) and [OrElse](#orelse) (`Or`, `Else`, `Catch`, `ContinueOnNone`) async extensions that allow chaining.

* Great interface that allows checking and extracting of data with a single method. See [TryGetValue](#trygetvalue) and [Match](#match).
* Explicit behavior of methods. See [GetValueOrThrow](#getvalueorthrow) and [GetValueOrDefault](#getvalueordefault). There is no `.Result` or `.Value` or `.Data` properties that have undefined or unexpected behavior if there are no succesful result.

* `TValue` and `TFault` generic parameters are not restricted in any way.
* There is no specific handling of null values. So you can store `nulls` as `TValue` or `TFault`. Use C# 8 nullable reference types to handle nulls.

* Assemblies contain only three `Result` type implementations and extension methods for them. There is no other stuff.

* `Result` has no third state. It is restricted by a schema and the compiler that only two states are possible in memory of an application. One of them is `HasValue`. Other one is `HasFault`. So there are no `bottom` or `empty` state.
* `Result` type implementations are if-less and make use of abstract classes polymorphism and VMT to maintain simplicity and error safety. As a result, there is no null-forgiving operator and no third state. Also, there are no ternary operators that check `Success` flag or similar stuff.
* [Inheritance](#inheritance) allows to freeze or limit generic `TFault` and `TValue` parameters with user custom type arguments.

## Drawbacks

* To enable some features the implementation is based on abstract classes polymorphism. So `Result` types are not marked `readonly` (but they are implemented as readonly) and are not `struct`.

## Instantiation of types

Explicit examples:
```csharp
var optional = Optional.Some("hello"); // Optional
var optional = Optional.Some("hello"); // Optional

var result = Result.Succeed("hello"); // Result
var result = Result.Succeed("hello"); // Result

var result = Result.Succeed(); // Result
var result = Result.Succeed(); // Result
```

```csharp
var optional = Optional.None(); // Optional
var optional = Optional.None(); // Optional

var result = ResultFailure.Create(new Exception()); // Result
var result = Result.Fail(new Exception()); // Result

var result = Result.Fail(new Exception()); // Result
var result = Result.Fail(new Exception()); // Result
```

Implicit examples:
```csharp
Optional optional = "hello";
Optional optional = Optional.None();

Result result = "hello";
Result result = new Exception();
Result result = Result.Succeed(55);
Result result = Result.Fail(0);

Result result = Result.Succeed();
Result result = new Exception();
```

```csharp
Optional optional = flag
? "Hello"
: Optional.None();

var optional = flag
? Optional.Some("Hello")
: Optional.None();

var optional = flag
? "Hello"
: Optional.None();

```

```csharp
Result result = flag
? "hello"
: new Exception();

var result = flag
? "hello"
: ResultFailure.Create(new Exception());

var result = flag
? Result.Succeed("hello")
: new Exception();

Result result = flag
? Result.Succeed(0)
: Result.Fail(-1);

var result = flag
? Result.Succeed(0)
: Result.Fail(-1);

var result = flag
? Result.Succeed(0)
: ResultFailure.Create(-1);
```

```csharp
Result = flag
? new Exception()
: Result.Succeed();

var result = flag
? Result.Fail(new Exception())
: Result.Succeed();

var result = flag
? new Exception()
: Result.Succeed();

```

Some conversions:
```csharp
Result source = ...

Result target = source;
```

```csharp
Optional GetResult(Random random)
{
int randomValue = random.Next(0, 10);
if (randomValue > 10)
{
return randomValue;
}

return Optional.None();
}
```

## Extraction of data from instances

### TryGetValue
```csharp
Optional optional = ...;

if (optional.TryGetValue(out string value))
{
// value is not null here
}

// value may be null here. If you used it, you would get "warning CS8602: Dereference of a possibly null reference"
```

```csharp
Result result = ...;

if (result.TryGetValue(out string value))
{
// value is not null here
}

// value may be null here. If you used it, you would get "warning CS8602: Dereference of a possibly null reference"
```

```csharp
Result result = ...;

if (result.TryGetValue(out string value, out Exception fault))
{
// value is not null here
// fault may be null here. If you used it, you would get "warning CS8602: Dereference of a possibly null reference"
}
else
{
// fault is not null here
// value may be null here. If you used it, you would get "warning CS8602: Dereference of a possibly null reference"
}

// Both value and fault may be null here. If you used any of them, you would get "warning CS8602: Dereference of a possibly null reference"

```

### TryGetFault
```csharp
Result result = ...;

if (result.TryGetFault(out Exception fault))
{
// fault is not null here
}

// fault may be null here. If you used it, you would get "warning CS8602: Dereference of a possibly null reference"
```

```csharp
Result result = ...;

if (result.TryGetFault(out Exception fault))
{
// fault is not null here
}

// fault may be null here. If you used it, you would get "warning CS8602: Dereference of a possibly null reference"
```

```csharp
Result result = ...;

if (result.TryGetFault(out Exception fault, out string value))
{
// fault is not null here
// value may be null here. If you used it, you would get "warning CS8602: Dereference of a possibly null reference"
}
else
{
// value is not null here
// fault may be null here. If you use it, you get "warning CS8602: Dereference of a possibly null reference"
}

// Both value and fault may be null here. If you used any of them, you would get "warning CS8602: Dereference of a possibly null reference"
```

### Match
```csharp
Optional optional = ...;

string extracted = optional.Match(onNone: () => "valueOnNone", onSome: i => $"Number {i}");
string extracted = optional.Match(onNone: () => "valueOnNone", onSome: () => "Number is present");
string extracted = optional.Match(onNone: () => "valueOnNone", onSomeValue: "Number is present");
string extracted = optional.Match(onNoneValue: "valueOnNone", onSome: i => $"Number {i}");
string extracted = optional.Match(onNoneValue: "valueOnNone", onSome: () => "Number is present");
string extracted = optional.Match(onNoneValue: "valueOnNone", onSomeValue: "Number is present");
```

Examples with upcast

```csharp
object upcasted = optional.Match(onNone: () => new object(), onSome: i => $"Number {i}");
object upcasted = optional.Match(onNone: () => new object(), onSome: () => "Number is present");
object upcasted = optional.Match(onNone: () => new object(), onSomeValue: "Number is present");
object upcasted = optional.Match(onNoneValue: new object(), onSome: i => $"Number {i}");
object upcasted = optional.Match(onNoneValue: new object(), onSome: () => "Number is present");
object upcasted = optional.Match(onNoneValue: new object(), onSomeValue: "Number is present");

object upcasted = optional.Match(onNone: () => "valueOnNone", onSome: _ => new object());
object upcasted = optional.Match(onNone: () => "valueOnNone", onSome: () => new object());
object upcasted = optional.Match(onNone: () => "valueOnNone", onSomeValue: new object());
object upcasted = optional.Match(onNoneValue: "valueOnNone", onSome: _ => new object());
object upcasted = optional.Match(onNoneValue: "valueOnNone", onSome: () => new object());
object upcasted = optional.Match(onNoneValue: "valueOnNone", onSomeValue: new object());

object upcasted = optional.Match(onNone: () => new Exception("There is no value"), onSome: i => $"Number {i}");
object upcasted = optional.Match(onNone: () => new Exception("There is no value"), onSome: () => "Number is present");
object upcasted = optional.Match(onNone: () => new Exception("There is no value"), onSomeValue: "Number is present");
object upcasted = optional.Match(onNoneValue: new Exception("There is no value"), onSome: i => $"Number {i}");
object upcasted = optional.Match(onNoneValue: new Exception("There is no value"), onSome: () => "Number is present");
object upcasted = optional.Match(onNoneValue: new Exception("There is no value"), onSomeValue: "Number is present");
```

```csharp
Result result = ...;

string extracted = result.Match(onFailure: ex => ex.Message, onSuccess: i => $"Number {i}");
string extracted = result.Match(onFailure: ex => ex.Message, onSuccess: () => "Number is present");
string extracted = result.Match(onFailure: ex => ex.Message, onSuccessValue: "Number is present");
string extracted = result.Match(onFailure: () => "valueOnNone", onSuccess: i => $"Number {i}");
string extracted = result.Match(onFailure: () => "valueOnNone", onSuccess: () => "Number is present");
string extracted = result.Match(onFailure: () => "valueOnNone", onSuccessValue: "Number is present");
string extracted = result.Match(onFailureValue: "valueOnNone", onSuccess: i => $"Number {i}");
string extracted = result.Match(onFailureValue: "valueOnNone", onSuccess: () => "Number is present");
string extracted = result.Match(onFailureValue: "valueOnNone", onSuccessValue: "Number is present");
```

Examples with upcast

```csharp
object upcasted = result.Match(onFailure: ex => new object(), onSuccess: i => $"Number {i}");
object upcasted = result.Match(onFailure: ex => new object(), onSuccess: () => "Number is present");
object upcasted = result.Match(onFailure: ex => new object(), onSuccessValue: "Number is present");
object upcasted = result.Match(onFailure: () => new object(), onSuccess: i => $"Number {i}");
object upcasted = result.Match(onFailure: () => new object(), onSuccess: () => "Number is present");
object upcasted = result.Match(onFailure: () => new object(), onSuccessValue: "Number is present");
object upcasted = result.Match(onFailureValue: new object(), onSuccess: i => $"Number {i}");
object upcasted = result.Match(onFailureValue: new object(), onSuccess: () => "Number is present");
object upcasted = result.Match(onFailureValue: new object(), onSuccessValue: "Number is present");

object upcasted = result.Match(onFailure: ex => ex.Message, onSuccess: _ => new object());
object upcasted = result.Match(onFailure: ex => ex.Message, onSuccess: () => new object());
object upcasted = result.Match(onFailure: ex => ex.Message, onSuccessValue: new object());
object upcasted = result.Match(onFailure: () => "valueOnNone", onSuccess: _ => new object());
object upcasted = result.Match(onFailure: () => "valueOnNone", onSuccess: () => new object());
object upcasted = result.Match(onFailure: () => "valueOnNone", onSuccessValue: new object());
object upcasted = result.Match(onFailureValue: "valueOnNone", onSuccess: _ => new object());
object upcasted = result.Match(onFailureValue: "valueOnNone", onSuccess: () => new object());
object upcasted = result.Match(onFailureValue: "valueOnNone", onSuccessValue: new object());

object upcasted = result.Match(onFailure: ex => ex.Message, onSuccess: i => $"Number {i}");
object upcasted = result.Match(onFailure: ex => ex.Message, onSuccess: () => "Number is present");
object upcasted = result.Match(onFailure: ex => ex.Message), onSuccessValue: "Number is present");
object upcasted = result.Match(onFailure: () => new Exception("There is no value"), onSuccess: i => $"Number {i}");
object upcasted = result.Match(onFailure: () => new Exception("There is no value"), onSuccess: () => "Number is present");
object upcasted = result.Match(onFailure: () => new Exception("There is no value"), onSuccessValue: "Number is present");
object upcasted = result.Match(onFailureValue: new Exception("There is no value"), onSuccess: i => $"Number {i}");
object upcasted = result.Match(onFailureValue: new Exception("There is no value"), onSuccess: () => "Number is present");
object upcasted = result.Match(onFailureValue: new Exception("There is no value"), onSuccessValue: "Number is present");
```

```csharp
Result result = ...;

string extracted = result.Match(onFailure: ex => ex.Message, onSuccess: () => "Fault is not present");
string extracted = result.Match(onFailure: ex => ex.Message, onSuccessValue: "Fault is not present");
string extracted = result.Match(onFailure: () => "valueOnNone", onSuccess: () => "Fault is not present");
string extracted = result.Match(onFailure: () => "valueOnNone", onSuccessValue: "Fault is not present");
string extracted = result.Match(onFailureValue: "valueOnNone", onSuccess: () => "Fault is not present");
string extracted = result.Match(onFailureValue: "valueOnNone", onSuccessValue: "Fault is not present");
```

Examples with upcast

```csharp
object upcasted = result.Match(onFailure: ex => new object(), onSuccess: () => "Fault is not present");
object upcasted = result.Match(onFailure: ex => new object(), onSuccessValue: "Fault is not present");
object upcasted = result.Match(onFailure: () => new object(), onSuccess: () => "Fault is not present");
object upcasted = result.Match(onFailure: () => new object(), onSuccessValue: "Fault is not present");
object upcasted = result.Match(onFailureValue: new object(), onSuccess: () => "Fault is not present");
object upcasted = result.Match(onFailureValue: new object(), onSuccessValue: "Fault is not present");

object upcasted = result.Match(onFailure: ex => ex.Message, onSuccess: () => new object());
object upcasted = result.Match(onFailure: ex => ex.Message, onSuccessValue: new object());
object upcasted = result.Match(onFailure: () => "valueOnNone", onSuccess: () => new object());
object upcasted = result.Match(onFailure: () => "valueOnNone", onSuccessValue: new object());
object upcasted = result.Match(onFailureValue: "valueOnNone", onSuccess: () => new object());
object upcasted = result.Match(onFailureValue: "valueOnNone", onSuccessValue: new object());

object upcasted = result.Match(onFailure: ex => ex.Message, onSuccess: () => "Fault is not present");
object upcasted = result.Match(onFailure: ex => ex.Message), onSuccessValue: "Fault is not present");
object upcasted = result.Match(onFailure: () => new Exception(), onSuccess: () => "Fault is not present");
object upcasted = result.Match(onFailure: () => new Exception(), onSuccessValue: "Fault is not present");
object upcasted = result.Match(onFailureValue: new Exception(), onSuccess: () => "Fault is not present");
object upcasted = result.Match(onFailureValue: new Exception(), onSuccessValue: "Fault is not present");
```

### Switch
```csharp
Optional optional = ...;

optional.Switch(
onNone: () => Console.WriteLine("There is no value"),
onSome: value => Console.WriteLine($"Value is {value}")
);

optional.Switch(
onNone: () => Console.WriteLine("There is no value"),
onSome: () => Console.WriteLine("Value is present")
);
```

```csharp
Result result = ...;

result.Switch(
onFailure: fault => Console.WriteLine("Fault is {fault.Message}"),
onSuccess: value => Console.WriteLine($"Value is {value}")
);

result.Switch(
onFailure: fault => Console.WriteLine("There is {fault.Message}"),
onSuccess: () => Console.WriteLine($"Value is present")
);

result.Switch(
onFailure: () => Console.WriteLine("Fault is present"),
onSuccess: value => Console.WriteLine($"Value is {value}")
);

result.Switch(
onFailure: () => Console.WriteLine("Fault is present"),
onSuccess: () => Console.WriteLine("Value is present")
);
```

```csharp
Result result = ...;

result.Switch(
onFailure: fault => Console.WriteLine("Fault is {fault.Message}"),
onSuccess: () => Console.WriteLine($"There is no fault")
); =

result.Switch(
onFailure: () => Console.WriteLine("Fault is present"),
onSuccess: () => Console.WriteLine("There is no fault")
);
```

### OnSome
```csharp
Optional optional = ...;

optional.OnSome(value => Console.WriteLine($"Value is {value}"));
optional.OnSome(() => Console.WriteLine("Value is present"));
```

### OnNone
```csharp
Optional optional = ...;

optional.OnNone(() => Console.WriteLine("There is no value"));
```

### OnSuccess
```csharp
Result result = ...;

result.OnSuccess(value => Console.WriteLine($"Value is {value}"));
result.OnSuccess(() => Console.WriteLine("Success"));
```

```csharp
Result result = ...;

result.OnSuccess(() => Console.WriteLine("Success"));
```

### OnFailure
```csharp
Result result = ...;

result.OnFailure(fault => Console.WriteLine($"Fault is {fault.Message}"));
result.OnFailure(() => Console.WriteLine("Failure"));
```

```csharp
Result result = ...;

result.OnFailure(fault => Console.WriteLine($"Fault is {fault.Message}"));
result.OnFailure(() => Console.WriteLine("Failure"));
```

### Switch/OnSome/OnNone/OnSuccess/OnFailure method chaining
```csharp
Optional optional = ...;

string result = optional
.Switch(
onNone: () => Console.WriteLine("There is no value"),
onSome: value => Console.WriteLine($"Value is {value}"))
.OnSome(value => Console.WriteLine($"Value is {value}"))
.OnNone(() => Console.WriteLine("There is no value"))
.Match(onNoneValue: "valueOnNone", onSome: value => value.ToString());
```

`Result` and `Result` have similar syntax.

### Switch/OnSome/OnNone/OnSuccess/OnFailure return value upcasting

```csharp
Optional optional = ...;

Optional upcasted = optional.Switch(
onNone: () => Console.WriteLine("There is no value"),
onSome: value => Console.WriteLine($"Value is {value}")
);
Optional upcasted = optional.Switch(
onNone: () => Console.WriteLine("There is no value"),
onSome: () => Console.WriteLine("Value is present")
);

Optional upcasted = optional.OnSome(value => Console.WriteLine($"Value is {value}"));
Optional upcasted = optional.OnSome(() => Console.WriteLine("Value is present"));

Optional upcasted = optional.OnNone(() => Console.WriteLine("There is no value"));
```

`Result` and `Result` have similar syntax.

### GetValueOrElse
```csharp
Optional optional = ...;

string extracted = optional.GetValueOrElse(() => "defaultValue");
string extracted = optional.GetValueOrElse("defaultValue");
```

Examples with upcast

```csharp
object upcasted = optional.GetValueOrElse(() => new object());
object upcasted = optional.GetValueOrElse(new object());

object upcasted = optional.GetValueOrElse(() => new Exception("There is no value"));
object upcasted = optional.GetValueOrElse(new Exception("There is no value"));

Optional objectOptional = ...;
object upcasted = objectOptional.GetValueOrElse(() => "defaultValue");
object upcasted = objectOptional.GetValueOrElse("defaultValue");
```

```csharp
Result result = ...;

string extracted = result.GetValueOrElse(fault => $"Converted to success fault: {fault.Message}");
string extracted = result.GetValueOrElse(() => "defaultValue");
string extracted = result.GetValueOrElse("defaultValue");
```

Examples with upcast

```csharp
object upcasted = result.GetValueOrElse(_ => new object());
object upcasted = result.GetValueOrElse(() => new object());
object upcasted = result.GetValueOrElse(new object());

object upcasted = result.GetValueOrElse(fault => new Exception(fault.Message));
object upcasted = result.GetValueOrElse(() => new Exception("There is no value"));
object upcasted = result.GetValueOrElse(new Exception("There is no value"));

Result objectResult = ...;
object upcasted = objectResult.GetValueOrElse(fault => fault.Message);
object upcasted = objectResult.GetValueOrElse(() => "defaultValue");
object upcasted = objectResult.GetValueOrElse("defaultValue");
```

### GetFaultOrElse
```csharp
Result result = ...;

Exception extracted = result.GetFaultOrElse(value => new Exception(value));
Exception extracted = result.GetFaultOrElse(() => new Exception());
Exception extracted = result.GetFaultOrElse(new Exception());
```

Examples with upcast

```csharp
object upcasted = result.GetFaultOrElse(_ => new object());
object upcasted = result.GetFaultOrElse(() => new object());
object upcasted = result.GetFaultOrElse(new object());

object upcasted = result.GetFaultOrElse(value => value);
object upcasted = result.GetFaultOrElse(() => "There is no fault");
object upcasted = result.GetFaultOrElse("There is no fault");

Result objectResult = ...;
object upcasted = objectResult.GetFaultOrElse(value => value);
object upcasted = objectResult.GetFaultOrElse(() => "defaultFault");
object upcasted = objectResult.GetFaultOrElse("defaultFault");
```

```csharp
Result result = ...;

Exception extracted = result.GetFaultOrElse(() => new Exception());
Exception extracted = result.GetFaultOrElse(new Exception());
```

Examples with upcast

```csharp
object upcasted = result.GetFaultOrElse(() => new object());
object upcasted = result.GetFaultOrElse(new object());

object upcasted = result.GetFaultOrElse(() => "There is no fault");
object upcasted = result.GetFaultOrElse("There is no fault");

Result objectResult = ...;
object upcasted = objectResult.GetFaultOrElse(() => "defaultFault");
object upcasted = objectResult.GetFaultOrElse("defaultFault");
```

### GetValueOrThrow
```csharp
Optional optional = ...;

string extracted = optional.GetValueOrThrow(); // Throws `ValueMissingException` on None
string extracted = optional.GetValueOrThrow(new Exception("There is no value"));
string extracted = optional.GetValueOrThrow(() => new Exception("There is no value"));

object upcasted = optional.GetValueOrThrow();
object upcasted = optional.GetValueOrThrow(new Exception("There is no value"));
object upcasted = optional.GetValueOrThrow(() => new Exception("There is no value"));
```

```csharp
Result result = ...;

string extracted = result.GetValueOrThrow(); // Throws `ResultFailedException` on Failure
string extracted = result.GetValueOrThrow(new Exception("There is no value"));
string extracted = result.GetValueOrThrow(() => new Exception("There is no value"));
string extracted = result.GetValueOrThrow(fault => new Exception(fault.Message));

object upcasted = result.GetValueOrThrow();
object upcasted = result.GetValueOrThrow(new Exception("There is no value"));
object upcasted = result.GetValueOrThrow(() => new Exception("There is no value"));
object upcasted = result.GetValueOrThrow(fault => new Exception(fault.Message));
```

To override exception thrown by default for a specific `TValue` you can implement an extension method with the specific `TValue` in your namespace. You can also use [inheritance](#inheritance) to override exception thrown by default for `TValue` in any namespace.

Example

```csharp
namespace CustomValues
{
class CustomValue
{
}
static class GetValueOrThrowExtensions
{
static CustomValue GetValueOrThrow(this Optional optional)
{
return optional.GetValueOrThrow(new Exception("Overiden!"));
}

static CustomValue GetValueOrThrow(this Result result)
{
return result.GetValueOrThrow(new Exception("Overiden!"));
}
}
}
```

### GetFaultOrThrow
```csharp
Result result = ...;

Exception extracted = result.GetFaultOrThrow(); // Throws `ResultSucceedException` on Success
Exception extracted = result.GetFaultOrThrow(new Exception("There is no fault"));
Exception extracted = result.GetFaultOrThrow(() => new Exception("There is no fault"));
Exception extracted = result.GetFaultOrThrow(value => new Exception(value));

object upcasted = result.GetFaultOrThrow();
object upcasted = result.GetFaultOrThrow(new Exception("There is no fault"));
object upcasted = result.GetFaultOrThrow(() => new Exception("There is no fault"));
object upcasted = result.GetFaultOrThrow(value => new Exception(value));
```

```csharp
Result result = ...;

Exception extracted = result.GetFaultOrThrow(); // Throws `ResultSucceedException` on Success
Exception extracted = result.GetFaultOrThrow(new Exception("There is no fault"));
Exception extracted = result.GetFaultOrThrow(() => new Exception("There is no fault"));

object upcasted = result.GetFaultOrThrow();
object upcasted = result.GetFaultOrThrow(new Exception("There is no fault"));
object upcasted = result.GetFaultOrThrow(() => new Exception("There is no fault"));
```

To override exception thrown by default exception for a specific `TFault` you can implement an extension method with the specific `TFault` in your namespace. You can also use [inheritance](#inheritance) to override exception thrown by default for `TFault` in any namespace.

Example

```csharp
namespace CustomFaults
{
class CustomFault
{
}
static class GetValueOrThrowExtensions
{
static CustomFault GetFaultOrThrow(this Result result)
{
return result.GetFaultOrThrow(new Exception("Overridden!"));
}

static CustomFault GetFaultOrThrow(this Result result)
{
return result.GetFaultOrThrow(new Exception("Overridden!"));
}
}
}
```

### GetValueOrDefault
```csharp
Optional optional = ...;

string? extracted = optional.GetValueOrDefault(); // null or actual value for reference types

object? upcasted = optional.GetValueOrDefault();
```

```csharp
Optional optional = ...;

int extracted = optional.GetValueOrDefault(); // 0 or actual value for the value type
```

```csharp
Result result = ...;

string? extracted = result.GetValueOrDefault(); // null or actual value for reference types

object? upcasted = result.GetValueOrDefault();
```

```csharp
Result result = ...;

int extracted = result.GetValueOrDefault(); // 0 or actual value for the value type
```

### GetFaultOrDefault
```csharp
Result result = ...;

Exception? extracted = result.GetFaultOrDefault(); // null or actual fault for reference types

object? upcasted = result.GetFaultOrDefault();
```

```csharp
Result result = ...;

int extracted = result.GetFaultOrDefault(); // 0 or actual fault for the value type
```

```csharp
Result result = ...;

Exception? extracted = result.GetFaultOrDefault(); // null or actual fault for reference types

object? upcasted = result.GetFaultOrDefault();
```

```csharp
Result result = ...;

int extracted = result.GetFaultOrDefault(); // 0 or actual fault for the value type
```

### GetValueOrNull
This method can be applied to non-nullable value types (structs) only.

```csharp
Optional optional = ...;

int? extracted = optional.GetValueOrNull(); // null or actual value
```

```csharp
Result result = ...;

int? extracted = result.GetValueOrNull(); // null or actual value
```

Upcasts are not supported.

### GetFaultOrNull
This method can be applied to non-nullable value types (structs) only.

```csharp
Result result = ...;

int? extracted = result.GetFaultOrNull(); // null or actual fault
```

```csharp
Result result = ...;

int? extracted = result.GetFaultOrNull(); // null or actual fault
```

Upcasts are not supported.

### EnsureHasValue
```csharp
Optional optional = ...;

// Nothing if `Some`
optional.EnsureHasValue(); // Throws `ValueMissingException` on None
optional.EnsureHasValue(new Exception("There is no value"));
optional.EnsureHasValue(() => new Exception("There is no value"))
```

To override exception thrown by default exception for a specific `TValue` you can implement an extension method with the specific `TValue` in your namespace. You can also use [inheritance](#inheritance) to override exception thrown by default for `TValue` in any namespace.

Example

```csharp
namespace Custom
{
class CustomValue
{
}
static class EnsureHasValueExtensions
{
static void EnsureHasValue(this Optional optional)
{
return optional.EnsureHasValue(new Exception("Overridden!"));
}
}
}
```

### EnsureNone
```csharp
Optional optional = ...;

// Nothing if `None`
optional.EnsureNone(); // Throws `ValueExistsException` if `Some`
optional.EnsureNone(new Exception("There is value"));
optional.EnsureNone(() => new Exception("There is value"))
optional.EnsureNone(value => new Exception($"There is value: {value}"))
```

To override exception thrown by default exception for a specific `TValue` you can implement an extension method with the specific `TValue` in your namespace. You can also use [inheritance](#inheritance) to override exception thrown by default for `TValue` in any namespace.

Example

```csharp
namespace Custom
{
class CustomValue
{
}
static class EnsureNoneExtensions
{
static void EnsureNone(this Optional optional)
{
return optional.EnsureNone(new Exception("Overridden!"));
}
}
}
```

### EnsureSuccess
```csharp
Result result = ...;

// Nothing if `Success`
result.EnsureSuccess(); // Throws `ResultFailedException` on Failure
result.EnsureSuccess(new Exception("There is no value"));
result.EnsureSuccess(() => new Exception("There is no value"))
result.EnsureSuccess(fault => new Exception(fault.Message))
```

```csharp
Result result = ...;

// Nothing if `Success`
result.EnsureSuccess(); // Throws `ResultFailedException` on Failure
result.EnsureSuccess(new Exception("It's failure"));
result.EnsureSuccess(() => new Exception("It's failure"))
result.EnsureSuccess(fault => new Exception(fault.Message))
```

To override exception thrown by default exception for a specific `TValue` or `TFault` you can implement an extension method with the specific `TValue` or `TFault` in your namespace. You can also use [inheritance](#inheritance) to override exception thrown by default for `TFault` or `TValue` in any namespace.

Example

```csharp
namespace CustomTypes
{
class CustomFault
{
}
class CustomValue
{
}
static class EnsureSuccessExtensions
{
static void EnsureSuccess(this Result result)
{
return result.EnsureSuccess(new Exception("Overridden!"));
}
static void EnsureSuccess(this Result result)
{
return result.EnsureSuccess(new Exception("Overridden!"));
}
}
}
```

### EnsureFailure
```csharp
Result result = ...;

// Nothing if `Failure`
result.EnsureFailure(); // Throws `ResultSucceedException` on Success
result.EnsureFailure(new Exception("There is no fault"));
result.EnsureFailure(() => new Exception("There is no fault"))
result.EnsureFailure(value => new Exception(value))
```

```csharp
Result result = ...;

// Nothing if `Failure`
result.EnsureFailure(); // Throws `ResultSucceedException` on Success
result.EnsureFailure(new Exception("It's success"));
result.EnsureFailure(() => new Exception("It's success"))
```

To override exception thrown by default exception for a specific `TValue` or `TFault` you can implement an extension method with the specific `TValue` or `TFault` in your namespace. You can also use [inheritance](#inheritance) to override exception thrown by default for `TFault`or `TValue` in any namespace.

Example

```csharp
namespace CustomTypes
{
class CustomFault
{
}
class CustomValue
{
}
static class EnsureFailureExtensions
{
static void EnsureFailure(this Result result)
{
return result.EnsureFailure(new Exception("Overridden!"));
}
static void EnsureFailure(this Result result)
{
return result.EnsureFailure(new Exception("Overridden!"));
}
}
}
```

### HasSome
```csharp
Optional optional = "has value";

bool extracted = optional.HasSome; // true
```

```csharp
Optional optional = Optional.None();

bool extracted = optional.HasSome; // false
```

### IsNone
```csharp
Optional optional = "has value";

bool extracted = optional.IsNone; // false
```

```csharp
Optional optional = Optional.None();

bool extracted = optional.IsNone; // true
```

### Success
```csharp
Result result = "has value";

bool extracted = result.Success; // true
```

```csharp
Result result = new Exception();

bool extracted = result.Success; // false
```

```csharp
Result result = Result.Succeed();

bool extracted = result.Success; // true
```

```csharp
Result result = new Exception();

bool extracted = result.Success; // false
```

### Failure
```csharp
Result result = "has value";

bool extracted = result.Failure; // false
```

```csharp
Result result = new Exception();

bool extracted = result.Failure; // true
```

```csharp
Result result = Result.Succeed();

bool extracted = result.Failure; // false
```

```csharp
Result result = new Exception();

bool extracted = result.Failure; // true
```

### LINQ method syntax (GetValues, GetFaults)
```csharp
Optional optional = ...;

// `[]` if `None`
// `[value]` if `Some`
IEnumerable values = optional
.GetValues()
.ToArray(); // optional

IEnumerable upcasted = optional.GetValues();
```

```csharp
Result result = ...;

// `[]` if `Failure`
// `[value]` if `Success`
IEnumerable values = result.GetValues().ToArray();

IEnumerable upcasted = result.GetValues();
```

```csharp
Result result = ...;

// `[exception]` if `Failure`
// `[]` if `Success`
IEnumerable faults = result.GetFaults().ToArray();

IEnumerable upcasted = result.GetFaults();
```

```csharp
Result result = ...;

// `[exception]` if `Failure`
// `[]` if `Success`
IEnumerable faults = result.GetFaults().ToArray();

IEnumerable upcasted = result.GetFaults();
```

### LINQ query syntax

There is no preferred way of combining the `IEnumerable` and `Optional` or `Result`.
You can choose a variant that suits your needs and implement it in your project.
Some variants are found in the tests folder.

Some examples:

#### Threat `Result` and `Optional` as containers with single or no elements

This is the simplest variant. But using it results in losing fault details.

##### Optional
```csharp
Optional optional = Optional.Some(10);

IEnumerable extracted =
from value in optional
from i1 in new [] { 1, 2 }
from i2 in new [] { 100, 200 }
select value + i1 + i2;

IEnumerable extracted =
from i1 in new [] { 1, 2 }
from value in optional
from i2 in new [] { 100, 200 }
select i1 + value + i2;

// extracted is [111, 112, 211, 212].
```

```csharp
Optional optional = Optional.Some(10);

IEnumerable extracted =
from value in optional
from i1 in new [] { 1, 2 }
from i2 in Array.Empty()
select value + i1 + i2;

IEnumerable extracted =
from i1 in new [] { 1, 2 }
from value in optional
from i2 in Array.Empty()
select i1 + value + i2;

// extracted is empty.
```

```csharp
Optional optional = Optional.None();

IEnumerable extracted =
from value in optional
from i in new [] { 1, 2 }
select value + i;

IEnumerable extracted =
from i in new [] { 1, 2 }
from value in optional
select value + i;

// extracted is empty.

```

To implement it you can use the code

```csharp
public static IEnumerable SelectMany(
this IOptional optional,
Func> collectionSelector,
Func resultSelector)
{
return optional.GetValues().SelectMany(collectionSelector, resultSelector);
}

public static IEnumerable SelectMany(
this IEnumerable collection,
Func> optionSelector,
Func resultSelector)
{
return collection.SelectMany(value => optionSelector(value).GetValues(), resultSelector);
}
```

##### Result
```csharp
Result result = Result.Succeed(10);

IEnumerable extracted =
from value in result
from i1 in new [] { 1, 2 }
from i2 in new [] { 100, 200 }
select value + i1 + i2;

IEnumerable extracted =
from i1 in new [] { 1, 2 }
from value in result
from i2 in new [] { 100, 200 }
select i1 + value + i2;

// extracted is [111, 112, 211, 212].
```

```csharp
Result result = Result.Succeed(10);

IEnumerable extracted =
from value in result
from i1 in new [] { 1, 2 }
from i2 in Array.Empty()
select value + i1 + i2;

IEnumerable extracted =
from i1 in new [] { 1, 2 }
from value in result
from i2 in Array.Empty()
select i1 + value + i2;

// extracted is empty.
```

```csharp
Result result = Result.Fail(new Exception());

IEnumerable extracted =
from value in result
from i in new [] { 1, 2 }
select value + i;

IEnumerable extracted =
from i in new [] { 1, 2 }
from value in result
select value + i;

// extracted is empty.

```

To implement it you can use the code

```csharp
public static IEnumerable SelectMany(
this IResult result,
Func> collectionSelector,
Func resultSelector)
{
return result.GetValues().SelectMany(collectionSelector, resultSelector);
}

public static IEnumerable SelectMany(
this IEnumerable collection,
Func> selector,
Func resultSelector)
{
return collection.SelectMany(value => selector(value).GetValues(), resultSelector);
}
```

#### Returning the first found fault

This is is the most useful way of combining data.

##### Optional

```csharp
Optional optional = Optional.Some(10);

Optional> extracted =
from value in optional
from i1 in new [] { 1, 2 }
from i2 in new [] { 100, 200 }
select value + i1 + i2;

Optional> extracted =
from i1 in new [] { 1, 2 }
from value in optional
from i2 in new [] { 100, 200 }
select i1 + value + i2;

// extracted is [111, 112, 211, 212].
```

```csharp
Optional optional = Optional.Some(10);

Optional> extracted =
from value in optional
from i1 in new [] { 1, 2 }
from i2 in Array.Empty()
select value + i1 + i2;

Optional> extracted =
from i1 in new [] { 1, 2 }
from value in optional
from i2 in Array.Empty()
select i1 + value + i2;

// extracted is empty.
```

```csharp
Optional optional = Optional.None();

Optional> extracted =
from value in optional
from i in new [] { 1, 2 }
select value + i;

Optional> extracted =
from i in new [] { 1, 2 }
from value in optional
select value + i;

// extracted is `None`.

```

To implement it, four `SelectMany` methods can be used

```csharp
static Optional> SelectMany(
this IEnumerable collection,
Func> optionalSelector,
Func resultSelector)
{
List results = new();
foreach (var item in collection)
{
if (!optionalSelector(item).TryGetValue(out var value))
return Optional.None();
results.Add(resultSelector(item, value));
}
return results;
}

static Optional> SelectMany(
this Optional> optional,
Func> collectionSelector,
Func resultSelector) =>
optional.MapValue(values => values.SelectMany(value => collectionSelector(value).Select(item => resultSelector(value, item))));

static Optional> SelectMany(
this Optional> optional,
Func> collectionSelector,
Func resultSelector) =>
optional.Match(
Optional>.None,
values => SelectMany(values, collectionSelector, resultSelector));

// To allow infinite chaining the following method could be placed in local namespace and other 3 methods can be placed in root namespace
static Optional> SelectMany(
this Optional optional,
Func> collectionSelector,
Func resultSelector) =>
optional.MapValue(value => collectionSelector(value).Select(item => resultSelector(value, item)));
```

##### Result
```csharp
Result result = Result.Succeed(10);

Result> extracted =
from value in result
from i1 in new [] { 1, 2 }
from i2 in new [] { 100, 200 }
select value + i1 + i2;

Result> extracted =
from i1 in new [] { 1, 2 }
from value in result
from i2 in new [] { 100, 200 }
select i1 + value + i2;

// extracted is [111, 112, 211, 212].
```

```csharp
Result result = Result.Succeed(10);

Result> extracted =
from value in result
from i1 in new [] { 1, 2 }
from i2 in Array.Empty()
select value + i1 + i2;

Result> extracted =
from i1 in new [] { 1, 2 }
from value in result
from i2 in Array.Empty()
select i1 + value + i2;

// extracted is empty.
```

```csharp
Result result = Result.Fail(new Exception("fault"));

Result> extracted =
from value in result
from i in new [] { 1, 2 }
select value + i;

Result> extracted =
from i in new [] { 1, 2 }
from value in result
select value + i;

// extracted is Exception("fault").

```

To implement it, four `SelectMany` methods can be used

```csharp
static Result> SelectMany(
this IEnumerable collection,
Func> selector,
Func resultSelector)
{
List results = new();
foreach (var item in collection)
{
if (selector(item).TryGetFault(out var fault, out var value))
return fault;
results.Add(resultSelector(item, value));
}
return results;
}

static Result> SelectMany(
this Result> result,
Func> collectionSelector,
Func resultSelector) =>
result.MapValue(values => values.SelectMany(value => collectionSelector(value).Select(item => resultSelector(value, item))));

static Result> SelectMany(
this Result> result,
Func> collectionSelector,
Func resultSelector) =>
result.Match(
Result>.Fail,
values => SelectMany(values, collectionSelector, resultSelector));

// To allow infinite chaining the following method could be placed in local namespace and other 3 methods can be placed in root namespace
static Result> SelectMany(
this Result result,
Func> collectionSelector,
Func resultSelector) =>
result.MapValue(value => collectionSelector(value).Select(item => resultSelector(value, item)));
```

### foreach
```csharp
string FindValue(Optional optional)
{
foreach(var value in optional)
{
return value + " is found!";
}

return "no value found";
}

```

```csharp
string FindValue(Result result)
{
foreach(var value in result)
{
return value + " is found!";
}

return "no value found";
}

```

### ToString
```csharp
Optional optional = ...;

// `None` if `None`
// `Some value={Value}` if `Some`
string str = optional.ToString();
```

```csharp
Result result = ...;

// `ResultFailure fault={Fault}` if `Failure`
// `ResultSuccess value={Value}` if `Success`
string str = result.ToString();
```

```csharp
Result result = ...;

// `ResultFailure fault={Fault}` if `Failure`
// `ResultSuccess` if `Success`
string str = result.ToString();
```

### Upcasts

You can upcast a return value of many data extraction methods by providing a type argument or by combining two arguments of different types in a single method call.

Examples:
```csharp
Optional optional = ...

Optional upcasted1 = optional.OnNone(str => Console.WriteLine(str));
Optional upcasted2 = optional.Match(onNone: () => new object(), onSome: str => str);
```

Only safe upcasts are allowed.
For example, `Optional` can be converted to `Optional` but not vice versa.

Safety is enforced by covariance rules. So:
* Upcasts are only supported for reference types because covariance can not be used with value types.
* Upcasts are only supported for synchronous methods because `Task` and `ValueTask` types do not support covariance.

## Conversion of generic arguments

All conversion methods except `Upcast` method support async extensions for every listed synchronous scenario.
All synchronous methods support upcasts of `TFault` and `TValue`.

Async extensions make use of methods returning `Task`, `ValueTask` and inline async lambdas. For example:
```csharp
async Task Get1(int number) => number + 1;
async ValueTask Get2(number) => number - 1;

Task> Get(Task> optional)
{
return optional
.MapValue(i => Get1(i))
.MapValue(i => Get2(i))
.MapValue(async i => await Get1(i));
}
```

If there is at least one async method in a chain returning `Task` the result is `Task`. Otherwise, the result is `ValueTask`.

### MapValue

`MapValue` changes value or/and type of `TValue`.

```csharp
Optional optional = ...;

Optional extracted = optional.MapValue(str => str + "suffix");
Optional extracted = optional.MapValue(() => "new value");
Optional extracted = optional.MapValue("other string");

Optional extracted = optional.MapValue(str => int.Parse(str));
Optional extracted = optional.MapValue(() => int.Parse("123"));
Optional extracted = optional.MapValue(15);
```

Async examples

```csharp
Optional optional = ...;

ValueTask> extracted = optional.MapValue(async str => await Task.FromResult(str));
ValueTask> extracted = optional.MapValue(str => new ValueTask(str));
Task> extracted = optional.MapValue(str => Task.FromResult(str));
```

```csharp
ValueTask> optional = ...;

ValueTask> extracted = optional.MapValue(str => str + "suffix");
ValueTask> extracted = optional.MapValue(async str => await Task.FromResult(str));
ValueTask> extracted = optional.MapValue(str => new ValueTask(str));
Task> extracted = optional.MapValue(str => Task.FromResult(str));
```

```csharp
Task> optional = ...;

Task> extracted = optional.MapValue(str => str + "suffix");
Task> extracted = optional.MapValue(async str => await Task.FromResult(str));
Task> extracted = optional.MapValue(str => new ValueTask(str));
Task> extracted = optional.MapValue(str => Task.FromResult(str));
```

```csharp
Result result = ...;

Result extracted = result.MapValue(str => str + "suffix");
Result extracted = result.MapValue(() => "new value");
Result extracted = result.MapValue("other string");

Result extracted = result.MapValue(str => int.Parse(str));
Result extracted = result.MapValue(() => int.Parse("123"));
Result extracted = result.MapValue(15);
```

Async examples

```csharp
Result result = ...;

ValueTask> extracted = result.MapValue(async str => await Task.FromResult(str));
ValueTask> extracted = result.MapValue(str => new ValueTask(str));
Task> extracted = result.MapValue(str => Task.FromResult(str));
```

```csharp
ValueTask> result = ...;

ValueTask> extracted = result.MapValue(str => str + "suffix");
ValueTask> extracted = result.MapValue(async str => await Task.FromResult(str));
ValueTask> extracted = result.MapValue(str => new ValueTask(str));
Task