Nito.Try
1.2.0
Prefix Reserved
dotnet add package Nito.Try --version 1.2.0
NuGet\Install-Package Nito.Try -Version 1.2.0
<PackageReference Include="Nito.Try" Version="1.2.0" />
paket add Nito.Try --version 1.2.0
#r "nuget: Nito.Try, 1.2.0"
// Install Nito.Try as a Cake Addin #addin nuget:?package=Nito.Try&version=1.2.0 // Install Nito.Try as a Cake Tool #tool nuget:?package=Nito.Try&version=1.2.0
Try
he Try monad (Error/Exceptional monad) for C#, particularly useful for railroad programming, e.g., with TPL Dataflow.
The Try Monad
Try<T>
is a simple kind of wrapper monad that represents either a value or an exception.
The API for this monad is not fully "pure". In particular, Try<T>
is not lazy in any way; it represents an exception or value that is already known. The Try<T>
type also has several helpers that make it more C#-friendly and less purely functional.
Wrapping
The standard way to wrap a value or exception is via Try.Create
. Try.Create
takes a delegate, which is executed immediately. If the delegate throws an exception, the resulting Try<T>
is a wrapper for that exception; if the delegate successfully returns a result, the resulting Try<T>
is a wrapper for that result value.
Try<int> t = Try.Create(() =>
{
MethodThatMayThrow();
return 13;
});
If you have a value or exception that you want to wrap directly, you can call Try.FromValue
or Try.FromException<T>
directly rather than using a delegate with Try.Create
:
Try<int> t1 = Try.FromValue(13);
Try<int> t2 = Try.FromException<int>(new InvalidOperationException());
Working with Try<T> Instances
You can transform one wrapped value into another wrapped value by calling Try<T>.Map
and passing it a delegate to do the transformation. If the current Try<T>
instance is an exception, then Map
immediately returns another wrapper for that exception; otherwise, Map
executes its delegate and returns a Try<T>
that is either a value or exception, depending on whether the Map
delegate throws.
Try<int> t1 = ...;
Try<int> t2 = t1.Map(value => checked(value * 2));
The normal monad-like APIs such as Bind
, Select
, and SelectMany
are also available. The latter two allow LINQ syntax:
Try<int> t1 = ...;
Try<int> t2 = ...;
Try<int> t3 = from v1 in t1
from v2 in t2
select v1 + v2;
Unwrapping
There are a variety of ways to extract the value or exception when you are ready to be done with the Try<T>
type. The most straightforward is Try<T>.Value
, which raises the exception if the instance is an exception, and returns the value otherwise.
Try<int> t1 = ...;
int v1 = t1.Value; // throws if t1 wraps an exception
You can also use the IsException
, IsValue
, and Exception
properties to determine if it's safe to access the Value
property.
Try<int> t1 = ...;
if (t1.IsValue)
Console.WriteLine(t1.Value);
Try<int> t1 = ...;
if (t1.IsException)
Console.WriteLine(t1.Exception);
Try<int> t1 = ...;
if (t1.Exception != null)
Console.WriteLine(t1.Exception);
Finally, you can use deconstruction to get the exception and value simultaneously.
Try<int> t1 = ...;
var (exception, value) = t1; // Does not throw, even if t1 wraps an exception.
// if `exception` is `null`, then `value` is a valid value.
A more "functional" or "monadic" way of processing results is the Match
method, which always runs one of its delegate arguments and not the other.
Try<int> t1 = ...;
string result = t1.Match(
exception =>
{
Console.WriteLine(exception);
return "error";
},
value =>
{
Console.WriteLine(value);
return "ok";
}
);
Don't Unwrap-Then-Wrap
Don't write code that unwraps Try<T>
values if they just end up being wrapped again. E.g., this is an antipattern:
// BAD CODE! Do not do this!
Try<int> t1 = ...;
Try<int> t2 = Try.Create(() =>
{
return t1.Value + 10;
});
In this case, if t1
is an exception, that exception will get raised at t1.Value
and then captured by Try.Create
. The semantics are correct, but this code pattern adds a new call stack to the exception, since it was thrown again. This can make debugging more complex.
Instead of unwrapping and wrapping again, use Map
:
// Same semantics as above, but better behavior with exceptions
Try<int> t1 = ...;
Try<int> t2 = t1.Map(v1 =>
{
return v1.Value + 10;
});
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 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. |
.NET Core | netcoreapp1.0 was computed. netcoreapp1.1 was computed. netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard1.0 is compatible. netstandard1.1 was computed. netstandard1.2 was computed. netstandard1.3 was computed. netstandard1.4 was computed. netstandard1.5 was computed. netstandard1.6 was computed. netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net45 was computed. net451 was computed. net452 was computed. net46 was computed. net461 is compatible. 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 | tizen30 was computed. tizen40 was computed. tizen60 was computed. |
Universal Windows Platform | uap was computed. uap10.0 was computed. |
Windows Phone | wp8 was computed. wp81 was computed. wpa81 was computed. |
Windows Store | netcore was computed. netcore45 was computed. netcore451 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.1
- No dependencies.
-
.NETStandard 1.0
- NETStandard.Library (>= 1.6.1)
-
.NETStandard 2.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.