[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/patch/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# 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`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/task-update.md>), [`LinkUpdate`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/link-update.md>), [`ResourceUpdate`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/resource-update.md>) and [`AssignmentUpdate`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/assignment-update.md>) 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

```csharp
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`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/patch.md#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

```csharp
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

```csharp
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

```csharp
public override string ToString()
```

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

## Static members

### Missing

```csharp
public static Patch<T> Missing { get; }
```

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

### Null

```csharp
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

```csharp
public static Patch<T> Of(T value)
```

A patch that sets the field to `value`.

## Operators

```csharp
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`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/patch.md#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`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/patch.md#properties>).

```csharp
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

```csharp
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
```

## Related

- [`TaskUpdate`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/task-update.md>) - the update record with the most patch fields
- [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>) - the change set that carries update records
- [Records, ids and dates](<https://docs.dhtmlx.com/planning-engine/net/records-ids-and-dates.md>) - patch fields alongside the other input types
- [Editing a project](<https://docs.dhtmlx.com/planning-engine/net/live-projects/editing-a-project.md>) - updating records in a live project
