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                
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="Nito.Try" Version="1.2.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Nito.Try --version 1.2.0                
#r "nuget: Nito.Try, 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 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                

Logo

Try Build status codecov NuGet version API docs

he Try monad (Error/Exceptional monad) for C#, particularly useful for railroad programming, e.g., with TPL Dataflow.

netstandard 1.0 netstandard 2.0

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.6.1

    • No dependencies.
  • .NETStandard 1.0

  • .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.

Version Downloads Last updated
1.2.0 310 12/8/2023
1.1.1 12,184 9/26/2021
1.1.0 973 10/3/2020
1.0.1 1,348 3/18/2019