• API Reference

    Show / Hide Table of Contents
    • Recore
      • AbsoluteUri
      • AsyncAction
      • AsyncAction<T>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7, T8>
      • AsyncAction<T1, T2, T3, T4, T5, T6, T7>
      • AsyncAction<T1, T2, T3, T4, T5, T6>
      • AsyncAction<T1, T2, T3, T4, T5>
      • AsyncAction<T1, T2, T3, T4>
      • AsyncAction<T1, T2, T3>
      • AsyncAction<T1, T2>
      • AsyncDefer
      • AsyncFunc<T, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, T7, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, T6, TResult>
      • AsyncFunc<T1, T2, T3, T4, T5, TResult>
      • AsyncFunc<T1, T2, T3, T4, TResult>
      • AsyncFunc<T1, T2, T3, TResult>
      • AsyncFunc<T1, T2, TResult>
      • AsyncFunc<TResult>
      • Defer
      • Either
      • Either<TLeft, TRight>
      • Func
      • ObjectExtensions
      • Of<T>
      • OfJsonAttribute
      • Optional
      • Optional<T>
      • RelativeUri
      • Result
      • Result.AsyncCatcher<TValue>
      • Result.Catcher<TValue>
      • Result<TValue, TError>
      • Unit
      • UriExtensions
    • Recore.Collections.Generic
      • AnonymousEqualityComparer<T>
      • ICollectionExtensions
      • IDictionaryExtensions
      • IIterator<T>
      • Iterator
      • LinkedListExtensions
      • ListExtensions
      • MappedComparer<T, TMapped>
      • MappedEqualityComparer<T, TMapped>
    • Recore.Linq
      • Renumerable
    • Recore.Security.Cryptography
      • SecureCompare
    • Recore.Text.Json.Serialization.Converters
      • OverrideEitherConverter<TLeft, TRight>
      • OverrideResultConverter<TValue, TError>
    • Recore.Threading.Tasks
      • TaskExtensions

    Struct Optional<T>

    Provides type-safe access to a nullable value.

    Implements
    IEquatable<Optional<T>>
    Inherited Members
    Object.Equals(Object, Object)
    Object.GetType()
    Object.ReferenceEquals(Object, Object)
    Namespace: Recore
    Assembly: Recore.dll
    Syntax
    [JsonConverter(typeof(OptionalConverter))]
    public struct Optional<T> : IEquatable<Optional<T>>
    Type Parameters
    Name Description
    T
    Remarks

    Optional<T> differs from Nullable<T> in the following ways:

    • Nullable<T> has syntactic sugar like the alias T? and the operators ?. and ??
    • Nullable<T> has some special-case behavior in the CLR for boxing and GetType()
    • Nullable<T> works only with value types while Optional<T> works with both value and reference types
    • Nullable<T> provides direct access to its value through Value, while Optional<T> requires access through its methods

    The last point is the most significant. Accessing the value directly through Value opens up the possibility for a NullReferenceException. With Optional<T>, once you have an optional value, all operations on it happen in an "optional context." You can't get rid of Optional<T> until you do something to handle the null case such as by calling Switch<TResult>(Func<T, TResult>, Func<TResult>) or ValueOr(T).

    Examples

    Here are a few examples for how to work with an optional value.

    Optional<T> has public constructors that you can use, but the easiest way to create an instance is to use the helper methods:

    Optional<string> opt;         // Optional is a value type, so this defaults to empty
    opt = "hello";                // Creates an Optional with the value "hello"
    opt = Optional<string>.Empty; // Now it's empty again
    

    Switch() is the main way to work with Optional. It's akin to a switch statement.

    opt.Switch(
        x => Console.WriteLine("Message: " + x),
        () => Console.WriteLine("No message"));
    

    You can also return a value like a switch expression. In this case, both legs of the Switch() must return the same type.

    int messageLength = opt.Switch(
        x => x.Length,
        () => -1);
    

    But, a more idiomatic way to handle the above case is to use OnValue(). This will map Optional<T> to Optional<U>. If the original Optional<T> is empty, the new one will also be empty.

    Optional<int> messageLength = opt.OnValue(x => x.Length);
    

    We can work with the value procedurally, but this doesn't get us access to the value. For that, we can use AssertValue(). It will try to retrieve the value and throw InvalidOperationException if there's no value.

    if (opt.HasValue)
    {
        string value = opt.AssertValue();
    }
    

    A safer way to get the value out is to use ValueOr(), which requires you to pass a fallback value.

    string message = opt.ValueOr(default);
    

    There's a special case where OnValue() and Then() can cause their callback to work differently than it does outside the Optional context. Consider these two calls:

    int? value = null;
    
    new Optional<int>(value ?? 0)
    new Optional<int?>(value).OnValue(x => x ?? 0)
    

    Normally, you'd expect these two lines to be equivalent for any function. But if value is null, they won't be the same.

    The same thing goes for Then():

    Optional<int> NullableToOptional(int? n) => Optional.Of(n ?? 0);
    
    NullableToOptional(value)
    new Optional<int?>(value).Then(NullableToOptional)
    

    The problem is that "null coalescing" operations (by which I mean any function that turns null into a non-null value, including the ?? operator) won't work as expected when passed through Optional<T>. This is because they will never receive null as an input.

    (A note to functional-programming aficionados: the first example has implications for associativity. Passing a composed function to OnValue() may produce a different result than two separate OnValue() calls if null coalescing is involved. The second example is the monad law of left identity.)

    Since any reference type can be null, there's no way to fix it except to avoid it. Just know that you can't perform null-coalescing inside of an Optional context. Rather, use Optional's own operations. Every example I can think of stands out as a bug if you examine it under this principle.

    For more information, this writeup explores the issue in the context of Java's optional type.

    Constructors

    | Improve this Doc View Source

    Optional(T)

    Creates an Optional<T> with a value.

    Declaration
    public Optional(T value)
    Parameters
    Type Name Description
    T value
    Remarks

    If null is passed for value, then the Optional<T> is considered empty.

    Properties

    | Improve this Doc View Source

    Empty

    Creates an Optional<T> without a value.

    Declaration
    public static Optional<T> Empty { get; }
    Property Value
    Type Description
    Optional<T>
    Remarks

    While an empty Optional<T> can also be created by calling the default constructor or passing null to the constructor, Empty is more expressive, making the absence of a value more obvious.

    | Improve this Doc View Source

    HasValue

    Indicates whether the Optional<T> was created with a value.

    Declaration
    public bool HasValue { get; }
    Property Value
    Type Description
    Boolean

    Methods

    | Improve this Doc View Source

    AssertValue()

    Extracts the value or throws an InvalidOperationException if the Optional<T> is empty.

    Declaration
    public T AssertValue()
    Returns
    Type Description
    T
    | Improve this Doc View Source

    Equals(Optional<T>)

    Determines whether this instance and another Optional<T> have the same values.

    Declaration
    public bool Equals(Optional<T> other)
    Parameters
    Type Name Description
    Optional<T> other
    Returns
    Type Description
    Boolean
    | Improve this Doc View Source

    Equals(Optional<T>, IEqualityComparer<T>)

    Determines whether this instance and another Optional<T> have the same values using the given IEqualityComparer<T>.

    Declaration
    public bool Equals(Optional<T> other, IEqualityComparer<T> comparer)
    Parameters
    Type Name Description
    Optional<T> other
    IEqualityComparer<T> comparer
    Returns
    Type Description
    Boolean
    | Improve this Doc View Source

    Equals(Object)

    Determines whether this instance and another object, which must also be an Optional<T>, have the same value.

    Declaration
    public override bool Equals(object obj)
    Parameters
    Type Name Description
    Object obj
    Returns
    Type Description
    Boolean
    Overrides
    ValueType.Equals(Object)
    | Improve this Doc View Source

    GetHashCode()

    Returns the hash code for the underlying type or zero if there is no value.

    Declaration
    public override int GetHashCode()
    Returns
    Type Description
    Int32
    Overrides
    ValueType.GetHashCode()
    | Improve this Doc View Source

    IfValue(Action<T>)

    Takes an action only if the Optional<T> has a value.

    Declaration
    public void IfValue(Action<T> onValue)
    Parameters
    Type Name Description
    Action<T> onValue
    | Improve this Doc View Source

    OnValue<TResult>(Func<T, TResult>)

    Maps a function over the Optional<T>'s value, or propagates Empty.

    Declaration
    public Optional<TResult> OnValue<TResult>(Func<T, TResult> f)
    Parameters
    Type Name Description
    Func<T, TResult> f
    Returns
    Type Description
    Optional<TResult>
    Type Parameters
    Name Description
    TResult
    | Improve this Doc View Source

    Switch(Action<T>, Action)

    Chooses an action to take depending on whether the Optional<T> has a value.

    Declaration
    public void Switch(Action<T> onValue, Action onEmpty)
    Parameters
    Type Name Description
    Action<T> onValue

    Called when the Optional<T> has a value.

    Action onEmpty

    Called when the Optional<T> does not have a value.

    | Improve this Doc View Source

    Switch<TResult>(Func<T, TResult>, Func<TResult>)

    Chooses a function to call depending on whether the Optional<T> has a value.

    Declaration
    public TResult Switch<TResult>(Func<T, TResult> onValue, Func<TResult> onEmpty)
    Parameters
    Type Name Description
    Func<T, TResult> onValue

    Called when the Optional<T> has a value.

    Func<TResult> onEmpty

    Called when the Optional<T> does not have a value.

    Returns
    Type Description
    TResult

    Result of the function that was called.

    Type Parameters
    Name Description
    TResult
    | Improve this Doc View Source

    Then<TResult>(Func<T, Optional<TResult>>)

    Chains another Optional<T>-producing operation onto the result of another.

    Declaration
    public Optional<TResult> Then<TResult>(Func<T, Optional<TResult>> f)
    Parameters
    Type Name Description
    Func<T, Optional<TResult>> f
    Returns
    Type Description
    Optional<TResult>
    Type Parameters
    Name Description
    TResult
    Remarks

    This is a monad bind operation. Conceptually, it is the same as passing f to OnValue<TResult>(Func<T, TResult>) and then "flattening" the Optionlt;Optional<T>> into an Optional<T>. (Note that Optionlt;Optional<T>> is not a valid Optional<T> because of the type constraint where T : class.)

    | Improve this Doc View Source

    ToEnumerable()

    Converts an optional value to an enumerable. The enumerable will have either zero or one elements.

    Declaration
    public IEnumerable<T> ToEnumerable()
    Returns
    Type Description
    IEnumerable<T>
    | Improve this Doc View Source

    ToString()

    Returns the value's string representation, or a localized "none" message.

    Declaration
    public override string ToString()
    Returns
    Type Description
    String
    Overrides
    ValueType.ToString()
    | Improve this Doc View Source

    ValueOr(T)

    Extracts the value with a fallback if the Optional<T> is empty.

    Declaration
    public T ValueOr(T fallback)
    Parameters
    Type Name Description
    T fallback
    Returns
    Type Description
    T

    Operators

    | Improve this Doc View Source

    Equality(Optional<T>, Optional<T>)

    Determines whether two instances of Optional<T> have the same value.

    Declaration
    public static bool operator ==(Optional<T> lhs, Optional<T> rhs)
    Parameters
    Type Name Description
    Optional<T> lhs
    Optional<T> rhs
    Returns
    Type Description
    Boolean
    | Improve this Doc View Source

    Explicit(Optional<T> to T)

    Casts this instance to its underlying value or the default value for the underlying type.

    Declaration
    public static explicit operator T(Optional<T> optional)
    Parameters
    Type Name Description
    Optional<T> optional
    Returns
    Type Description
    T
    | Improve this Doc View Source

    Implicit(T to Optional<T>)

    Converts an instance of a type to an optional value.

    Declaration
    public static implicit operator Optional<T>(T value)
    Parameters
    Type Name Description
    T value
    Returns
    Type Description
    Optional<T>
    | Improve this Doc View Source

    Inequality(Optional<T>, Optional<T>)

    Determines whether two instances of Optional<T> have different values.

    Declaration
    public static bool operator !=(Optional<T> lhs, Optional<T> rhs)
    Parameters
    Type Name Description
    Optional<T> lhs
    Optional<T> rhs
    Returns
    Type Description
    Boolean

    Implements

    System.IEquatable<T>

    Extension Methods

    ObjectExtensions.StaticCast<T>(T)
    ObjectExtensions.Apply<T, TResult>(T, Func<T, TResult>)
    ObjectExtensions.Apply<T>(T, Action<T>)
    • Improve this Doc
    • View Source
    Back to top Generated by DocFX