For the complete documentation index, see llms.txt. This page is also available as Markdown.

Consume

Methods that end the chain and hand you a plain value.

Everything on this page takes you out of the Option. To keep chaining, see Transform.

IsSome and IsNone

bool IsSome { get; }
bool IsNone { get; }

The state, as a bool. Properties, not methods.

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

maybeName.IsSome; // true
maybeName.IsNone; // false

Good for a short-circuit or a guard. Reach for Match when both branches matter.

IsSomeAnd

bool IsSomeAnd(Predicate<T> predicate)

There is a value and it passes the predicate.

Option<string> maybePatron = Option.Some("The Raven Queen");
maybePatron.IsSomeAnd(patron => patron.Length > 0); // true

IsNoneOr

There is no value, or the one there passes.

Match

Both branches, one plain value out. This is the default way to end a chain.

On a None: length is 0 — the onNone branch runs and onSome does not.

Match also has the state overload that saves the most, because a capturing call pays for two delegates. See Match saves the most.

Pattern matching with Deconstruct

From 7.0.0 the case types deconstruct, so C# pattern matching binds the value positionally.

Three Deconstruct methods exist across both types, and only three:

Type
Signature
Binds

Some<T>

Deconstruct(out T value)

The contained value

Ok<TOk, TErr>

Deconstruct(out TOk value)

The Ok value

Err<TOk, TErr>

Deconstruct(out TErr error)

The error

Each is documented as never handing you null.

None has none, deliberately

There is nothing to bind, and option is None<string> already tests the case.

So option is None<string>(), with the parentheses, is a compile error rather than a redundant spelling. An empty positional pattern still needs a Deconstruct to bind against:

Write it without the parentheses.

You cannot deconstruct the monad itself

Deconstruct is on the case types, not on Option<T>. So this does not compile:

There is no state-plus-value tuple to destructure. Test the case first, then bind.

Where Match still wins

A switch expression over the closed hierarchy warns, even with both cases covered:

The hierarchy really is closed — an internal member stops anything outside the assembly deriving from Option<T> — but the compiler's exhaustiveness check has no knowledge of that idiom. Silencing the warning means an unreachable arm:

Match needs neither. It takes exactly two branches, both required, and returns a value with no warning to suppress.

So use Match when you want a value out of both cases, which is most of the time. Reach for a positional pattern in statement position — an if guarding a block, a switch statement, a when clause — where Match would mean wrapping statements in a lambda that returns nothing.

A positional pattern does not trip WM2021. That rule reports a property pattern reading IsSome, IsNone, IsOk or IsErr — a state check written so nothing recognises it as one. A positional pattern reads none of those properties. See WM2021.

Unwrap

The value, or a throw.

On a None: throws UnwrapException.

An intentional point of failure, like First on an empty sequence. Use it only when you have established the value is there upstream. Otherwise reach for Match.

UnwrapOr

The value, or the fallback you already have.

UnwrapOrElse

The same, but the factory runs only on a None. Use it when the fallback costs something to build.

UnwrapOrDefault

The value, or default(T).

UnwrapOrNull

The value, or null — a real Nullable<T>, so absence stays visible. An extension method, in Waystone.Monads.Options.Extensions.

Constrained to T : struct, so it does not appear on an Option<string>. A reference type needs no equivalent — UnwrapOrDefault already gives null.

Expect

Like Unwrap, but you supply the message the exception carries.

On a None: throws UnmetExpectationException carrying your message.

Use it where an absent value means a logic error rather than a runtime condition to recover from.

MapOr

Transforms the value, or returns your fallback. Unlike Map, it ends the chain.

MapOrElse

The same, building the fallback lazily.

Its state overload threads the same state through both delegates — see MapOrElse threads state through both delegates.

MapOrDefault

The same, falling back to default(TOut), so you write no fallback at all.

MapOrNull

The same, falling back to null. This one is on Option<T> itself, so it needs no extra using — unlike UnwrapOrNull, which is an extension.

Constrains its result to TOut : struct. Map to a reference type and MapOrDefault already gives you null.

Last updated

Was this helpful?