QueryKey
A structured, ordered cache key with value equality on a canonical form. Segment order matters; dictionary segments are normalised by sorting their keys.
public sealed class QueryKey : IEquatable<QueryKey>Members#
Of#
Creates a key from ordered segments: QueryKey.Of("todos", "detail", 5).
Supported segment types: strings, numeric primitives, bool, char,
Guid, DateTime, DateTimeOffset, DateOnly,
TimeOnly, TimeSpan, enums, null, collections of
these, string-keyed dictionaries, and any type implementing IQueryKeySegment.
Throws ArgumentException for no segments or an unsupported segment type —
failing loudly at the call site beats a silently colliding cache entry.
FromString#
The named equivalent of the implicit string conversion. Null and whitespace-only input yields null — no key.
implicit operator#
Keeps QueryKey = "todos" call sites compiling and meaning
QueryKey.Of("todos"). Null or whitespace converts to null — no key.
StartsWith#
True when this key's leading segments equal every segment of prefix —
["todos", 1] starts with ["todos"]. Compared segment-by-segment
on canonical forms, never as a string prefix of the whole hash, so ["todo"]
does not match ["todos"].
Equality#
Value equality on the canonical form.
ToString#
The canonical form, e.g. ["todos",{"page":2}].
Canonicalisation rules#
- Strings are quoted and escaped, so
["a,b"]and["a","b"]cannot collide. - Numbers, dates and times use the invariant culture.
- Enums use their numeric value — a member can be renamed without silently changing cached identity.
- Dictionaries must be string-keyed and are written with keys in ordinal order, so property order in an ad-hoc filter object doesn't change identity.
- Collections nest, to a maximum depth of 32 (guards against cyclic graphs).
- Computed by hand rather than with a JSON serializer, keeping the package dependency-free and trimming/AOT-safe.
IQueryKeySegment#
IQueryKeySegment#
Lets a custom type participate as a key segment. ToKeySegment() must return a
stable, deterministic string: equal values equal strings, distinct values distinct
strings, across sessions — it participates directly in the key's identity. Deliberately an
interface rather than reflection over arbitrary objects: key hashing runs on every cache
lookup and must stay trimming- and AOT-safe. Anonymous types therefore cannot be segments —
use a Dictionary<string, object?> or a named type implementing this
interface.