Option<T>

Control Flow

IsSomeAnd

Use IsSomeAnd when you want to check if the Option is a Some and that the value contained inside the Some matches a predicate.

Option<string> maybeName = Option.Some("Raven");
maybeName.IsSomeAnd(name => name.Length > 0); // true

IsNoneOr

Use IsNoneOr when you want to check if the Option is a None or the value contained inside the Some matches a predicate.

Option<string> maybeName = Option.Some("Queen");
maybeName.IsNoneOr(name => name.Length > 0); // true
maybeName.IsNoneOr(name => string.IsNullOrWhiteSpace(name)); // false

Transform

Refer to the Transform section on the Core Functionality page to learn about the other transform methods available for an Option<T>

FlatMap

Use FlatMap to compose monadic pipelines where each operation might fail and return an Option<T> itself. It prevents nested Option<Option<T>> results and keeps the pipeline flat and clean.

Option<string> TryExtractDomain(string email);

Option<string> maybeEmail = GetEmail(userId);
Option<string> maybeDomain = maybeEmail.FlatMap(TryExtractDomain);

Without FlatMap, you'd need to Map and then flatten manually, or deal with nested options.

FlatMap short-circuits: if one of the options in the chain is None, the subsequent functions are skipped.

Filter

Use Filter to retain only the values that pass a predicate. If the value doesn't match, the result becomes a None.

Option<string> maybeName = Option.Some("Thordak");

Option<string> nonEmpty = maybeName.Filter(name => name.Length > 0); // Some("Thordak")
Option<string> blank = maybeName.Filter(name => name.Length == 0);   //  None

This is the clean alternative to if-guards. It keeps the monadic flow and makes intent obvious.

Zip

Use Zip to combine two options into a single option containing both values as a tuple.

Option<string> a = Option.Some("a");
Option<string> b = Option.Some("b");
Option<string> c = Option.None<string>();

Option<(string, string)> ab = a.Zip(b); // Some(("a", "b"))
Option<(string, string)> ac = a.Zip(c); // None

If either Option being zipped is a None, then a None will be returned.

Unzip

Reverses a Zip, splitting the tuple into two options.

Option<(string, string)> some = Option.Some(("a", "b"));
Option<(string, string)> none = Option.None<(string, string)>();

(Option<string>, Option<string>) unzippedSome = some.Unzip(); // (Some("a"), Some("b"))
(Option<string>, Option<string>) unzippedNone = none.Unzip(); // (None, None)

Logical Operators

Sometimes you want to combine two Option values using logical operators without leaving the monadic model.

Or

Or returns the first Some value encountered in the chain.

Option<string> first = Option.Some("John");
Option<string> second = Option.None<string>();
Option<string> fallback = Option.Some("Default");

Option<string> result = first.Or(second).Or(fallback); // Some("John")

Use Or when you want a prioritized fallback chain

OrElse

Like Or, but lazily evaluated. The fallback is only invoked if the preceding is None.

Option<string> first = Option.None<string>();

Option<string> CreateSecond() => Option.None<string>();
Option<string> CreateFallback() => Option.Some("Default");

Option<string> result = first
    .OrElse(() => CreateSecond())
    .OrElse(() => CreateFallback()); // Some("Default")

Xor

Xor is an exclusive-or. It returns the first Some value encountered in the chain if exactly one of the options is Some.

Option<string> first = Option.Some("Art");
Option<string> second = Option.None<string>();
Option<string> third = Option.Some("Dad");

Option<string> result = first
    .Xor(second) // Some("Art")
    .Xor(third); // None

Xor is niche, but useful when you're checking mutually exclusive conditions

Last updated

Was this helpful?