Proxoft.Optional
1.2.0
dotnet add package Proxoft.Optional --version 1.2.0
NuGet\Install-Package Proxoft.Optional -Version 1.2.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="Proxoft.Optional" Version="1.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Proxoft.Optional --version 1.2.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Proxoft.Optional, 1.2.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 Proxoft.Optional as a Cake Addin #addin nuget:?package=Proxoft.Optional&version=1.2.0 // Install Proxoft.Optional as a Cake Tool #tool nuget:?package=Proxoft.Optional&version=1.2.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Optional
Optional objects: Option<T>, Either<Left, Right>
Usage
public record Entity(int Id, int Value);
public class Repository
{
private List<Entity> _entities = new List<Entity>();
public Option<Entity> FindBy(int id)
{
Entity? entity = _entities.SingleOrDefault(e => e.Id == id);
return entity.WhenNotNull();
}
public Either<string, Entity> Create(int value)
{
if (value < 0)
{
return "cannot create entity with value less then 0";
}
int newId = (_entities.LastOrDefault()?.Id ?? 0) + 1;
Entity newEntity = new(newId, value);
_entities.Add(newEntity);
return newEntity;
}
public Either<string, Entity> Update(int id, int value)
{
if (_entities.All(e => e.Id != id))
{
return $"entity with id {id} does not exist";
}
if (value < 0)
{
return $"cannot update entity {id} with value {value} which is less then 0";
}
int index = _entities.FindIndex(e => e.Id == id);
_entities[index] = _entities[index] with
{
Value = value
};
return _entities[index];
}
public Option<string> Delete(int id)
{
if (_entities.All(e => e.Id != id))
{
return $"entity with id {id} does not exist";
}
_entities.RemoveAll(e => e.Id == id);
return None.Instance;
}
}
Console.WriteLine("Let's try options!");
Repository repo = new();
string message = "";
Console.WriteLine();
Console.WriteLine("== Create entity ==");
Console.WriteLine();
message = repo
.Create(15)
.Reduce(
e => $"entity with id {e.Id} created",
e => e
);
Console.WriteLine(message);
message = repo
.Create(-2)
.Reduce(
e => $"entity with id {e.Id} created",
e => e
);
Console.WriteLine(message);
message = repo
.Create(9)
.Reduce(
e => $"entity with id {e.Id} created",
e => e
);
Console.WriteLine(message);
Console.WriteLine();
Console.WriteLine("== Find entity ==");
Console.WriteLine();
Option<Entity> entity = repo
.FindBy(id: 1);
message = entity
.Map(e => $"entity {e.Id} has value is {e.Value}")
.Reduce($"entity with id {1} not found");
Console.WriteLine(message);
Console.WriteLine();
Console.WriteLine("== Find and update entity ==");
Console.WriteLine();
entity = repo
.FindBy(id: 11);
message = entity
.Map(e => $"entity {e.Id} has value is {e.Value}")
.Reduce($"entity with id {11} not found");
Console.WriteLine(message);
message = repo
.FindBy(id: 1)
.Either(none: "not found")
.Map(maybe => TrySetValueAndSave(maybe))
.Reduce(
e => $"entity {e.Id} has value is {e.Value}",
error => error
);
Console.WriteLine(message);
message = repo
.FindBy(id: 2)
.Either(none: "not found")
.Map(maybe => TrySetValueAndSave(maybe))
.Reduce(
e => $"entity {e.Id} has value is {e.Value}",
error => error
);
Console.WriteLine(message);
message = repo
.FindBy(id: 3)
.Either(none: "3 not found")
.Map(maybe => TrySetValueAndSave(maybe)) // won't be executed at all
.Reduce(
e => $"entities value is {e.Value}",
error => error
);
Console.WriteLine(message);
Either<string, Entity> TrySetValueAndSave(Either<string, Entity> entity)
{
return entity
.Map(e => e with
{
Value = e.Value - 10
})
.Map(e => repo.Update(e.Id, e.Value));
}
System.Text.Json serialization
JsonSerializerOptions options = new();
options.Converters.Add(new OptionJsonConverter());
options.Converters.Add(new EitherJsonConverter());
Option<int> maybeNumber = 25;
Option<decima> maybeOtherNumber = None.Instance;
string json1 = JsonSerialize.Serialize(mabeNumber, option);
// returns
// {
// "option": "some",
// "value": 25
// }
string json2 = JsonSerialize.Serialize(maybeOtherNumber, option);
// returns
// {
// "option": "none"
// }
Option<int> desMaybeNumber = JsonSerialize.Deserialize<Option<int>>(json1, option);
// desMaybeNumber is Some<int>(25)
Option<decima> desMaybeOtherNumber = JsonSerialize.Deserialize<Option<int>>(json2, option);
// desMaybeNumber is None
Either<string, int> stringOrInt = 49;
string json3 = JsonSerialize.Serialize(mabeNumber, option);
// returns
// {
// "either": "right",
// "value": 49
// }
Either<string, decima> stringOrDecimal = "not a number";
string json4 = JsonSerialize.Serialize(mabeNumber, option);
// returns
// {
// "either": "left",
// "value": "not a number"
// }
Either<string, int> desStringOrInt = JsonSerialize.Deserialize<Either<string, int>>(json3, option);
// desStringOrInt == new Right<string, int>(49)
Either<string, decimal> desStringOrDecimal = JsonSerialize.Deserialize<Either<string, int>>(json4, option);
// desStringOrInt == new Left<string, int>("not a number")
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. 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 is compatible. 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.
-
net6.0
- No dependencies.
-
net8.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.