-
Notifications
You must be signed in to change notification settings - Fork 2
Option User Guide
This guide describes the programming interface of Option<T> and Maybe<T>. An executable version of the code presented below can be found in OptionDemo.
Option<T> and Maybe<T> provide essentially the same programming interface as Nullable<T> (T? for short), but allow T to be either any type or a class type, respectively.
Just like T?, Option<T> can be initialized with null, default, or any valid value of type T:
double? nullDouble = null;
Option<string> nullString = null;
double? someDouble = 3.14;
Option<string> someString = "foo";We introduce a Print helper function so as to keep the code examples concise:
static void Print(object value = default) => Console.WriteLine(value);We can check the presence of a valid value with HasValue:
Print(nullDouble.HasValue); // False
Print(nullString.HasValue); // False
Print(someDouble.HasValue); // True
Print(someString.HasValue); // TrueWe employ another helper function for dealing with exceptions:
static object TryCatch<T>(Func<T> func)
{
try { return func(); } catch (Exception ex) { return $"{ex.GetType()}: {ex.Message}"; }
}Property Value provides direct access to the value stored in Option<T>:
Print(someDouble.Value); // 3.14
Print(someString.Value); // foo
Print(TryCatch(() => nullDouble.Value)); // System.InvalidOperationException: Nullable object must have a value.
Print(TryCatch(() => nullString.Value)); // System.InvalidOperationException: Nullable object must have a value.One can also access the value with an explicit cast:
Print((double)someDouble); // 3.14
Print((string)someString); // foo
Print(TryCatch(() => (double)nullDouble)); // System.InvalidOperationException: Nullable object must have a value.
Print(TryCatch(() => (string)nullString)); // System.InvalidOperationException: Nullable object must have a value.Access the value or return default(T) using method GetValueOrDefault():
Print(nullDouble.GetValueOrDefault()); // 0
Print(nullString.GetValueOrDefault()); //
Print(someDouble.GetValueOrDefault()); // 3.14
Print(someString.GetValueOrDefault()); // fooOr provide a custom default value:
Print(nullDouble.GetValueOrDefault(42)); // 42
Print(nullString.GetValueOrDefault("bar")); // bar
Print(someDouble.GetValueOrDefault(42)); // 3.14
Print(someString.GetValueOrDefault("bar")); // fooThe null coalescing operator (??) is not directly supported on Option<T>. Instead, we call the method GetValueOr(Func<T>). That is, we provide a function that can supply a default value similar to this one:
static T Computation<T>(T value)
{
Print("running computation ...");
return value;
}We can use it in GetValueOr(Func<T>) like so:
Print(nullDouble ?? Computation(42.0)); // running computation ... 42
Print(nullString.GetValueOr(() => Computation("bar"))); // running computation ... bar
Print(someDouble ?? Computation(42.0)); // 3.14
Print(someString.GetValueOr(() => Computation("bar"))); // fooWe can use the same construct to throw custom exceptions when there is no valid value:
Print(TryCatch(() => nullDouble ?? throw new Exception("missing double"))); // System.Exception: missing double
Print(TryCatch(() => nullString.GetValueOr(() => throw new Exception("missing string")))); // System.Exception: missing string
Print(TryCatch(() => someDouble ?? throw new Exception("missing double"))); // 3.14
Print(TryCatch(() => someString.GetValueOr(() => throw new Exception("missing string")))) // foo