Patch<T>#

A three-state field of an update record. A patch is Missing (keep the current value), Null (clear it) or carries a value (set it). Every editable field of TaskUpdate, LinkUpdate, ResourceUpdate and AssignmentUpdate is a Patch<T>, and a new update record starts with every patch Missing.

Build one with Patch<T>.Missing, Patch<T>.Null or Patch<T>.Of(value), or assign a T and the implicit conversion wraps it.

Declaration#

public readonly struct Patch<T> : IEquatable<Patch<T>>

Patch<T> is an immutable value type. default(Patch<T>) is Missing.

Properties#

Property Type Description
Kind PatchKind Which of the three states this patch is in.
IsMissing bool true when Kind is Missing.
IsNull bool true when Kind is Null.
HasValue bool true when Kind is Value.
Value T The carried value. Throws InvalidOperationException when the patch is Missing or Null.

Methods#

TryGetValue#

public bool TryGetValue(out T value)

Returns true and the carried value when the patch has one. Returns false for Missing and Null; value is then default(T).

Equals#

public bool Equals(Patch<T> other)
public override bool Equals(object? obj)

Two patches are equal when they're in the same state and, for Value, their values are equal by EqualityComparer<T>.Default. Missing equals Missing, and Null equals Null.

GetHashCode() follows the same rule.

ToString#

public override string ToString()

Returns "Missing", "Null" or "Value(...)" with the carried value, e.g. "Value(3)".

Static members#

Missing#

public static Patch<T> Missing { get; }

A patch that leaves the field unchanged. Same as default(Patch<T>).

Null#

public static Patch<T> Null { get; }

A patch that clears the field. What clearing means depends on the field: an optional field is cleared, a field with a default goes back to that default, and a required field rejects the operation. Each update record's page lists its fields.

Of#

public static Patch<T> Of(T value)

A patch that sets the field to value.

Operators#

public static implicit operator Patch<T>(T value)
public static bool operator ==(Patch<T> a, Patch<T> b)
public static bool operator !=(Patch<T> a, Patch<T> b)

The implicit conversion calls Of(value), so update.Duration = 3 sets the field. == and != compare like Equals.

The conversion also accepts a null reference for a reference type T: Patch<Id> p = null! produces Of(null) with Kind Value, not Null. To clear a field, assign Patch<T>.Null.

PatchKind#

The state of a Patch<T>, returned by Kind.

public enum PatchKind
{
    Missing,
    Null,
    Value,
}
Value Description
Missing The field is absent; the current value stays. The default.
Null The field is an explicit null; the current value is cleared.
Value The field carries a new value.

Example#

using Plen;

var update = new TaskUpdate("design")
{
    Duration = 3,                            // Patch<double>.Of(3)
    ConstraintDate = Patch<Moment>.Null,     // clear the constraint date
};                                           // every other field stays Missing

Console.WriteLine(update.Duration);          // Value(3)
Console.WriteLine(update.Progress.Kind);     // Missing

if (update.Duration.TryGetValue(out var duration))
    Console.WriteLine(duration);             // 3

Console.WriteLine(update.ConstraintDate == Patch<Moment>.Null);   // True