Use Nullable Values

Preserve absence as data without allocating an object or inventing a sentinel.

BeginnerCore.BaseSource-checked

Goal and component

Represent a value that may be absent without allocating an object or using a sentinel. Nullable<T> belongs to Core.Base and wraps std::optional<T>.

set(SHARP_RUNTIME_COMPONENTS Core.Base)
target_link_libraries(app PRIVATE SharpRuntime::Core.Base)

Create present and absent values

#include <System/Nullable.hpp>

System::Nullable<int> missing;
System::Nullable<int> score = 42;

if (!missing.getHasValueProperty() &&
    score.getHasValueProperty()) {
    const int value = score.getValueProperty();
    (void)value;
}

A default value is absent. Construction from T is intentionally implicit, mirroring the convenient C# conversion from T to T?. getValueProperty() returns a const reference and throws InvalidOperationException when absent.

Choose a fallback

const int defaultLimit = missing.GetValueOrDefault();   // int{} == 0
const int configured = missing.GetValueOrDefault(100); // explicit policy

Prefer the explicit overload when the domain fallback is not the type’s default. Do not translate every C# ?? into zero or empty text by convention.

Equality has a floating-point nuance

Nullable::Equals uses the runtime’s default-equality policy, which treats two floating NaNs as equal and supplies a matching hash. operator== models C# lifted == and uses the underlying operator, so two nullable NaNs compare false. That asymmetry is deliberate and tested.

Nullable is not pointer ownership

NeedUse
Optional small/value typeNullable<T> or std::optional<T>
Optional exclusive objectstd::unique_ptr<T>
Observer that may expirestd::weak_ptr<T>
Borrow that is either present or absentDocumented raw pointer

The contained T still controls copy, move, destruction, and cost. Avoid Nullable<unique_ptr<T>> unless three states are genuinely required.

Verify the edge cases

  • Absent Value throws the expected Sharp Runtime exception.
  • Fallback is evaluated according to your own control flow.
  • Copy/move behavior of a resource-owning T is acceptable.
  • Equality and hash policy match the dictionary/set comparer that consumes it.