LunarDoggo.Optionals
1.0.1
dotnet add package LunarDoggo.Optionals --version 1.0.1
NuGet\Install-Package LunarDoggo.Optionals -Version 1.0.1
<PackageReference Include="LunarDoggo.Optionals" Version="1.0.1" />
paket add LunarDoggo.Optionals --version 1.0.1
#r "nuget: LunarDoggo.Optionals, 1.0.1"
// Install LunarDoggo.Optionals as a Cake Addin #addin nuget:?package=LunarDoggo.Optionals&version=1.0.1 // Install LunarDoggo.Optionals as a Cake Tool #tool nuget:?package=LunarDoggo.Optionals&version=1.0.1
LunarDoggo.Optionals
This library was inspired by a project at university where we had to implement an extension to Java optionals. C# provides an alternative to optionals with the null-conditional (?
) and null-coalescing (??
) operators, but there is no easy way to return error messages to calling methods by using these operators without throwing Exceptions or returning custom objects that can contain a value or an error message.
This library's main goal is to provide an easy way for bubbling exceptions and messages up to calling methods without needing an uncountable amount of try-catch-blocks and if-statements. To achieve this goal, the library distinguishes between three kinds of optionals:
- those which contain values
- those which contain only a message
- those which contain a message and an exception
Usage
1. Creating optionals
using LunarDoggo.Optionals;
[...]
void SomeMethod()
{
//Create an optional containing a value
IOptional<int> value = Optional.OfValue<int>(12);
//Create an optional containing a message
IOptional<int> message = Optional.OfMessage<int>("Insert your message here");
//Create an optional containing an exception
IOptional<int> exception = Optional.OfException<int>(new ArgumentException("Some message"));
//Create an optional containing an exception and a custom message
IOptional<int> exception = Optional.OfException<int>(new ArgumentException("Some exception"), "Custom message");
//Create an optional from a collection of optionals of the same generic type
IOptional<IEnumerable<int>> values = Optional.OfOptionals<IEnumerable<int>>(new[] { Optional.OfValue<int>(1), [...] });
}
Optional.OfMessage<T>(string)
, Optional.OfException<T>(Exception)
and Optional.OfException<T>(Exception, string)
are mainly used when mapping an optional using the methods IOptional<T>.FlatMap<S>(Func<T, IOptional<S>>)
and IOptional<T>.SafeFlatMap<S, V>(Func<T, IOptional<S>>)
in order to
2. Map between different types of optionals
using LunarDoggo.Optionals;
[...]
void SomeMethod()
{
IOptional<string> value = Optional.Of<string>("123");
//Map to int
IOptional<int> map = value.Map(_str => Int32.Parse(_str)); //does not catch exceptions
IOptional<int> safeMap = value.SafeMap<int, FormatException>(_str => Int32.Parse(_str)); //catches Exceptions of the provided type and returns an IOptional<T> containing the caught Exception if one was caught
//FlatMap to int; useful for example for validation
IOptional<int> flatMap = value.FlatMap(_str => {
int i = Int32.Parse(_str);
if(i > 100)
return Optional.OfMessage<int>("Expected a value less or equal to 100");
return Optional.OfValue<int>(i);
}); //does not catch exceptions
IOptional<int> safeFlatMap = value.FlatMap<int, FormatException>(_str => {
int i = Int32.Parse(_str);
if(i > 100)
return Optional.OfMessage<int>("Expected a value less or equal to 100");
return Optional.OfValue<int>(i);
}); //catches Exceptions of the provided type and returns an IOptional<T> containing the caught Exception if one was caught
}
Please be aware that optionals that contain a message or an Exception
will always return an optional containing the same message or Exception
, the provided mapping functions will not be executed
3. Apply changes to an optional:
using LunarDoggo.Optionals;
[...]
void SomeMethod()
{
//Apply something to the contained value (only changes the contained value if the optional contains an object of a mutable reference type)
IOptional<int[]> values = Optional.OfValue<int[]>(new int[] { 1, 2, 3 }).Apply(_values => _values[1] = 10); //sets the second value in the array contained in the optional to 10
}
Please be aware that optionals that contain a message or an Exception
will not execute the provided action
4. Extract values from an optional without using the Value property:
using LunarDoggo.Optionals;
[...]
void SomeMethod()
{
IOptional<string> value = Optional.Of<string>("123");
//Convert an optional to a string
string intValue = value.ToString(_str => _str + "!"); //returns "123!" in this example
string message = Optional.OfMessage<int>("Some message").ToString(_i => _i); //returns "Some message"
//Get the contained value or an alternative
string val1 = value.OrElse("Empty"); //Returns "123" in this example
int val2 = Optional.OfMessage<int>("Message").OrElse(123); //returns 123
int val3 = Optional.OfMessage<int>("Message").OrElse(() => 321); //returns 321
}
API
Methods and properties provided by every IOptional<T>
object:
Method/Property | Description
---|---
bool HasValue { get; }
| Returns whether the optional contains a value
T Value { get; }
| Returns the contained value if it is present otherwise, a NotSupportedException is thrown
bool HasMessage { get; }
| Returns whether the optional contains a message
string Message { get; }
| Returns the contained message if it is present, otherwise a NotSupportedException is thrown
bool HasException { get; }
| Returns whether the optional contains an Exception
IOptional<S> SafeFlatMap<S, V : Exception>(Func<T, IOptional<S>>)
| maps this optional to an optional of type S
. Use this version if you want to catch a specific kind of exception
IOptional<S> SafeFlatMap(Func<T, IOptional<S>>)
| maps this optional to an optional of type S
. Use this version if you want to catch any kind of exception
IOptional<S> FlatMap(Func<T, IOptional<S>>)
| maps this optional to an optional of type S
IOptional<S> SafeMap<S, V : Exception>(Func<T, S>)
| maps this optional to an optional of type S
. Use this version if you want to catch a specific kind of exception
IOptional<S> SafeMap(Func<T, S>)
| maps this optional to an optional of type S
. Use this version if you want to catch any kind of exception
IOptional<S> Map(Func<T, S>)
| maps this optional to an optional of type S
IOptional<T> Map(Action<T>)
| applies an Action<T>
to the contained value
IOptional<T> IfHasException(Action<Exception>)
| the provided action is executed if the optional contains an exception
IOptional<T> IfHasMessage(Action<string>)
| the provided action is executed if the optional contains a message
IOptional<T> IfHasValue(Action<T>)
| the provided action is executed if the optional contains a value
string ToString(Func<T, string>)
| converts the contained value to a string if it is present, otherwise the contained message is returned
T OrElseThrow(Exception)
| Returnes the contained value if it is present, otherwise the provided exception is thrown
T OrElse(Func<T>)
| Returnes the contained value if it is present, otherwise the result of provided function returning an object of type T
is returned
T OrElse(T)
| Returnes the contained value if it is present, otherwise the provided parameter of type T
is returned
Note: the methods IfHasValue and Apply functionally behave the same way, but IfHasValue is intended to call other code if a value is contained, whereas Apply is intended to be used to alter the contained value itself
Methods provided by the static class Optional
:
Method | Description
---|---
IOptional<T> OfValue<T>(T)
| Creates a new IOptional<T>
containing the provided value
IOptional<T> OfMessage<T>(string)
| Creates a new IOptional<T>
containing the provided message
IOptional<T> OfException<T>(Exception)
| Creates a new IOptional<T>
containing the provided Exception
IOptional<T> OfException<T>(Exception, string)
| Creates a new IOptional<T>
containing the provided Exception
and custom message
IOptional<IEnumerable<T>> OfOptionals<T>(IEnumerable<IOptional<T>>)
| Creates a new IOptional<IEnumerable<T>>
containing the value of all provided IOptional<T>
objects. If any of the provided objects contains an Exception
, the resulting optional contains all Exception
s, if any of the provided objects contains a message, all Messages will be concatenated to a single one and an optional containing this message will be returned instead
Extension methods provided by the static class Optional
:
Extension method | Description
---|---
IOptional<IEnumerable<T>> Filter<T>(Func<T, bool>)
| Filters all values contained in the optional and returns an optional that only contains the items that match the provided filter
IOptional<S> ForEach<S, T>(Action<T>) where S : IEnumerable<T>
| Applies the provided action to every item of the optional's contained collection
IOptional<S> Convert<T, S, V>(Func<T, S>)
| Returns an optional that contains the same values as the provided optional but with another kind of collection derived from IEnumerable<V>
IOptional<S> Cast<T, S, V>()
| Returns an optional that contains the same collection as the calling optional, but with a type cast applied to it
Product | Versions 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. |
-
.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.
This library provides optionals that can contain either a value or a message or an Exception with a message
- implemented API for mapping between optional types
- added functionality to catch Exceptions when mapping between optional types
- added methods to extract values with alternatives from optionals
This version includes alternatives to some methods that don't require you to provide as many generic parameters as the original ones at compile time. This change includes:
- IOptional.SafeFlatMap,
- IOptional.SafeMap,
- Optional.OfOptionals