CkUuid
Job: read a UUID from any way people write it, and hand it back in the one spelling you can store, compare and derive from.
A UUID (universally unique identifier — .NET calls the type Guid) is a 128-bit
identifier written as 32 hex digits, like 08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f. The
trouble is that systems spell the same identifier many ways: with hyphens, without
them, wrapped in braces or parentheses, prefixed with urn:uuid:, in either casing.
CkUuid reads all of those — plus a boxed Guid straight off a database reader — and
writes back the lowercase hyphenated form, so two spellings of one identifier always
match. One rule matters most here: there is no substitute fallback. An identifier
names one specific thing, and an invented one is worse than none — it corrupts
deduplication and audit trails. A value that cannot be used answers "" (string
methods) or Guid.Empty (the all-zeros Guid), and the all-zeros UUID itself counts
as missing by default, because that is what databases and serializers emit when
nobody set a value.
Quick look
using SafeCoder.CommonKit;
CkUuid.Canonical("{08D3F9C6-5E4A-4B8F-9D2E-7A1B3C5D7E9F}"); // -> "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"
CkUuid.ToGuid("junk"); // -> Guid.Empty (rejected)
CkUuid.ToGuidOrNull("00000000-0000-0000-0000-000000000000"); // -> null (all zeros = missing)
CkUuid.Version("08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"); // -> 4
CkUuid.IsUuid("junk"); // -> false
CkUuid.SameUuid("{08D3F9C6-5E4A-4B8F-9D2E-7A1B3C5D7E9F}", "08d3f9c65e4a4b8f9d2e7a1b3c5d7e9f"); // -> true
CkUuid.IsVersion("08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f", 4, 7); // -> true
Guid id = CkUuid.NewV7(); // sorts by creation time
CkUuid.Explain("junk"); // -> "not a UUID in a known shape"
Methods
Canonical
The one agreed spelling.
string Canonical(
object? input = null,
bool treatZerosAsMissing = true,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
treatZerosAsMissing |
bool |
true |
Counts the all-zeros UUID as missing rather than real. Pass false to read it as a real value. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering "", when the value cannot be used. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| The value is a UUID in any supported shape | The canonical text: "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f" |
The canonical text: "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f" |
| Rejected: missing, oversized, not a UUID in a known shape, or — by default — all zeros | Empty string | Throws CkUuidException — carries Input, Expected and Reason |
There is deliberately no substitute fallback — an invented identifier is worse than an empty one.
Reads a UUID from any supported shape and writes it lowercase, hyphenated, no braces — the form to store and compare.
CkUuid.Canonical("{08D3F9C6-5E4A-4B8F-9D2E-7A1B3C5D7E9F}"); // -> "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"
CkUuid.Canonical("08d3f9c65e4a4b8f9d2e7a1b3c5d7e9f"); // -> "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"
CkUuid.Canonical("urn:uuid:08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"); // -> "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"
CkUuid.Canonical("00000000-0000-0000-0000-000000000000"); // -> "" (zeros mean missing)
CkUuid.Canonical("not an id"); // -> "" (rejected)
Format
One of the four everyday shapes.
string Format(
object? input = null,
string? into = "D",
bool treatZerosAsMissing = true,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
into |
string? |
"D" |
The shape to write: "D" hyphenated, "N" 32 bare digits, "B" braced, "P" parenthesized — always lowercase. Anything else is rejected. |
treatZerosAsMissing |
bool |
true |
Counts the all-zeros UUID as missing rather than real. Pass false to read it as a real value. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering "", when the value or the shape cannot be used. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
The value is a UUID and into is one of the four shapes |
The formatted text: "08d3f9c65e4a4b8f9d2e7a1b3c5d7e9f" with into: "N" |
The formatted text: "08d3f9c65e4a4b8f9d2e7a1b3c5d7e9f" with into: "N" |
Rejected: a bad value, or a shape that is not D, N, B or P |
Empty string | Throws CkUuidException — carries Input, Expected and Reason |
The value itself is read the way Canonical reads one.
For systems that store one of the other spellings. The into parameter names the
shape: "D" hyphenated (the default), "N" 32 bare digits, "B" braced, "P"
parenthesized — always lowercase.
CkUuid.Format(
input: "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f",
into: "D"
); // -> "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"
CkUuid.Format(
input: "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f",
into: "N"
); // -> "08d3f9c65e4a4b8f9d2e7a1b3c5d7e9f"
CkUuid.Format(
input: "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f",
into: "B"
); // -> "{08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f}"
CkUuid.Format(
input: "08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f",
into: "P"
); // -> "(08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f)"
The two typed readers, ToGuid and ToGuidOrNull, both take treatZerosAsMissing
(default true). Switch it off only when the all-zeros value really means something
in your data:
CkUuid.ToGuidOrNull(
input: "00000000-0000-0000-0000-000000000000",
treatZerosAsMissing: false
); // -> Guid.Empty, read as a real value
ToGuid
The typed reader.
Guid ToGuid(
object? input = null,
bool treatZerosAsMissing = true,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
treatZerosAsMissing |
bool |
true |
Counts the all-zeros UUID as missing rather than real. Pass false to read it as a real value — and lose the unambiguous sentinel. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering Guid.Empty, when the value cannot be used. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| The value is a UUID in any supported shape | The Guid 08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f |
The Guid 08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f |
| Rejected: missing, oversized, not a UUID in a known shape, or — by default — all zeros | Guid.Empty |
Throws CkUuidException — carries Input, Expected and Reason |
No fallback parameter, on purpose — rejection is always Guid.Empty, never a made-up id.
ToGuid reads the same shapes but answers a Guid — for Entity Framework keys,
dictionary lookups and comparisons.
CkUuid.ToGuid("{08D3F9C6-5E4A-4B8F-9D2E-7A1B3C5D7E9F}"); // -> the Guid 08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f
CkUuid.ToGuid("junk"); // -> Guid.Empty (rejected)
ToGuidOrNull
Null when there is nothing usable.
Guid? ToGuidOrNull(
object? input = null,
bool treatZerosAsMissing = true
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
treatZerosAsMissing |
bool |
true |
Reads the all-zeros UUID as missing, so it comes back as null too. Pass false to hand it back as Guid.Empty. |
Returns
| When | You get |
|---|---|
| The value is a UUID in any supported shape | The Guid 08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f |
Missing, unreadable, or a sentinel: null, DBNull, "junk", an unsupported type, or — by default — the all-zeros UUID |
null — this method never throws |
An honest nothing is never an error, and neither is anything else — null is the answer for whatever cannot be used.
Works like ToGuid but answers null instead when there
is nothing usable: a missing value (null or DBNull), one that cannot be read, or —
by default — the all-zeros UUID. That way a nullable database column receives NULL
rather than an empty GUID, and is null replaces comparing against the sentinel.
CkUuid.ToGuidOrNull("junk"); // -> null
CkUuid.ToGuidOrNull(null); // -> null (nothing there — an honest answer)
CkUuid.ToGuidOrNull("00000000-0000-0000-0000-000000000000"); // -> null (zeros mean missing)
FromName
The same UUID from the same name, every time.
Guid FromName(
object? name = null,
object? space = null,
int version = 5,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
name |
object? |
null |
The name to derive from: text, or a whole number written invariantly. At most CkSettings.MaxUuidNameLength (1,024) characters — over that is rejected, never truncated. |
space |
object? |
null |
The name-space UUID, in any shape Canonical reads — one of the RFC spaces (NamespaceDns, NamespaceUrl…) or, better for your own ids, one minted once per id family. |
version |
int |
5 |
5 (SHA-1, recommended) or 3 (MD5, legacy interop only). Anything else is rejected. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering Guid.Empty, when a value cannot be used. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| The name and name space are usable | The derived Guid: 2ed6657d-e927-568b-95e1-2665a8aea6a2 for "www.example.com" in NamespaceDns |
The derived Guid: 2ed6657d-e927-568b-95e1-2665a8aea6a2 for "www.example.com" in NamespaceDns |
| Rejected: a missing or oversized name, a name space that cannot be read, or a version other than 5 and 3 | Guid.Empty |
Throws CkUuidException — carries Input, Expected and Reason |
A bad ingredient never derives a wrong id — it is rejected instead.
Derives a name-based UUID from two ingredients: a name space (itself a UUID, marking which family of ids you are in) and a name. The derivation is deterministic — the same name space and name always give the same UUID, on every platform and in every language. That is the point: an identifier can be computed instead of stored. "Which event UUID belongs to claim 12345" needs no mapping table — derive it again and you get the same answer, which also makes retries and reruns safe, since the same occurrence always produces the same id.
The default is version 5, which hashes with SHA-1 (a hash is a fixed-size fingerprint
computed from data); pass version: 3 for MD5, only when you must match a system that
already derives with it. The class ships the RFC 9562 name spaces — NamespaceDns,
NamespaceUrl, NamespaceOid, NamespaceX500 — but for your own ids it is better to
mint one fresh UUID per id family, once, and hard-code it.
CkUuid.FromName(
name: "www.example.com",
space: CkUuid.NamespaceDns
); // -> the Guid 2ed6657d-e927-568b-95e1-2665a8aea6a2 — here, in Python, everywhere
CkUuid.FromName(
name: "www.example.com",
space: CkUuid.NamespaceDns,
version: 3
); // -> the Guid 5df41881-3aed-3515-88a7-2f4a814cf09e (the MD5 variant)
The name is hashed exactly as given, byte for byte — no trimming, no case-folding — because a derived identifier must match what every other system derives from the same name. A whole number works as a name too (written invariantly), and a name over 1,024 characters is rejected rather than truncated, since truncating would change the id.
Version
Which kind of UUID this is.
int Version(
object? input = null,
int fallback = 0,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
fallback |
int |
0 |
What comes back when the value cannot be used — 0 by default, which no version is. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering the fallback, when the value cannot be used. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| The value is a UUID | The version digit: 4 |
The version digit: 4 |
| Rejected: missing, not a UUID in a known shape, or all zeros — always missing here | The fallback (default 0) |
Throws CkUuidException — carries Input, Expected and Reason |
The one method with a fallback parameter — it answers a plain int, not an identity.
Reads the UUID's version digit: 4 is random, 5 and 3 are name-based, 7 is time-ordered, 1 is the classic time-and-MAC kind.
CkUuid.Version("08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"); // -> 4 (random)
Guid derived = CkUuid.FromName(
name: "www.example.com",
space: CkUuid.NamespaceDns
);
CkUuid.Version(derived); // -> 5 (name-based)
CkUuid.Version("junk"); // -> 0 (the default fallback)
IsUuid
Does it read as a UUID at all?
bool IsUuid(
object? input = null,
bool treatZerosAsMissing = true,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
treatZerosAsMissing |
bool |
true |
Counts the all-zeros UUID as missing rather than real. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering false, when the value is not a UUID. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| The value reads as a UUID under the readers' rules | true |
true |
| Rejected: missing, not a UUID in a known shape, a wrong type, or all zeros with the default on | false |
Throws CkUuidException — carries Input, Expected and Reason |
The yes-or-no form of Canonical and ToGuid: the four text
shapes, the urn:uuid: prefix, any casing, a boxed Guid. When the value is going to be
stored, read it with ToGuidOrNull instead and check for null — same
question, and you get the value back.
CkUuid.IsUuid("{08D3F9C6-5E4A-4B8F-9D2E-7A1B3C5D7E9F}"); // -> true
CkUuid.IsUuid("00000000-0000-0000-0000-000000000000"); // -> false (missing by default)
CkUuid.IsUuid("junk"); // -> false
IsNil
Is it the all-zeros UUID?
bool IsNil(
object? input = null,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering false, when the value is not a UUID. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
The value reads as a UUID and is 00000000-0000-0000-0000-000000000000 |
true |
true |
| Any other UUID | false |
false |
| Rejected: not a UUID | false |
Throws CkUuidException — carries Input, Expected and Reason |
RFC 9562 calls it the nil UUID; it is what databases and serializers emit when nobody set
a value, the 1900-01-01 of identifiers. The readers turn it into "missing" silently; this
method says so out loud, for data-quality checks and for telling "nobody set it" from
"not an id". The same job CkDate.IsPlaceholder does for dates.
CkUuid.IsNil("00000000-0000-0000-0000-000000000000"); // -> true
CkUuid.IsNil(Guid.Empty); // -> true
CkUuid.IsNil("junk"); // -> false (not a UUID at all)
IsCanonical
Is it written in the canonical spelling?
bool IsCanonical(
object? input = null,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The raw value. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering false, when the value is not canonical UUID text. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| Text that is exactly the lowercase, hyphenated, 36-character form | true |
true |
A UUID in another dressing — braces, bare digits, upper case, urn:uuid: — or a boxed Guid |
false |
Throws — the reason says it is a UUID in another form |
| Rejected: not a UUID at all | false |
Throws CkUuidException — carries Input, Expected and Reason |
A shape check for API contracts and columns that must hold canonical text, the same idea
as CkCountry.IsAlpha2. Surrounding whitespace and markup are
cleaned away first; then the spelling must be exactly what Canonical would
write. The all-zeros UUID is canonical-shaped, so true here — whether it means anything
is IsUuid's question. To accept any shape and store the canonical spelling, read
the value with Canonical instead.
CkUuid.IsCanonical("08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"); // -> true
CkUuid.IsCanonical("08D3F9C6-5E4A-4B8F-9D2E-7A1B3C5D7E9F"); // -> false (upper case)
CkUuid.IsCanonical("{08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f}"); // -> false (braces)
IsStandard
Is it an RFC 9562 UUID?
bool IsStandard(
object? input = null,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering false, when the value is not a UUID. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
The value reads as a UUID whose variant bits are the standard 10xx |
true |
true |
| Another variant: the legacy Microsoft or NCS layouts, the reserved variant, all ones | false |
false |
| Rejected: not a UUID, or all zeros — always missing here | false |
Throws CkUuidException — carries Input, Expected and Reason |
The variant is what makes the Version digit meaningful: Version reads the
digit as written, and a random sixteen bytes dressed as a UUID has one too. Pair the two
when an id must be a real RFC 9562 UUID of a given kind.
CkUuid.IsStandard("08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f"); // -> true (variant 9)
CkUuid.IsStandard("08d3f9c6-5e4a-4b8f-cd2e-7a1b3c5d7e9f"); // -> false (variant c: the Microsoft layout)
CkUuid.IsStandard(Guid.NewGuid()); // -> true
IsVersion
Is it one of these kinds?
bool IsVersion(
object? input = null,
params IEnumerable<int> versions
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
versions |
params IEnumerable<int> |
— | The version digits to accept, 1 to 8. |
Returns
| When | You get |
|---|---|
| The value reads as a UUID and its version digit is listed | true |
| It is not a UUID, the digit is not listed, the list is empty, or the value is all zeros | false — an answer, not a failure; it never throws |
For "random or time-ordered ids only": IsVersion(id, 4, 7). Read the way
Version reads it — the digit as written, zeros always missing. A params list
must be last, so there is no throwIfInvalid; call Version with it first when you need
the exception. Pair with IsStandard when the digit must be meaningful.
CkUuid.IsVersion("08d3f9c6-5e4a-4b8f-9d2e-7a1b3c5d7e9f", 4, 7); // -> true
CkUuid.IsVersion("2ed6657d-e927-568b-95e1-2665a8aea6a2", 4, 7); // -> false (a v5)
IsFromName
Does this id still match its natural key?
bool IsFromName(
object? input = null,
object? name = null,
object? space = null,
int version = 5,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The UUID to check: text in any everyday shape, or a boxed Guid. |
name |
object? |
null |
The name to derive from: text, or a whole number written invariantly. Hashed exactly as given. |
space |
object? |
null |
The name space UUID, in any shape Canonical reads. |
version |
int |
5 |
5 (SHA-1) or 3 (MD5), matching how the id was derived. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says which part cannot be used and why, instead of answering false. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| The value reads as a UUID and equals the one FromName derives | true |
true |
| It reads, and is a different UUID | false |
false |
| Rejected: the value is not a UUID, or the name, space or version cannot be used | false |
Throws CkUuidException — carries Input, Expected and Reason |
FromName(name, space) == ToGuid(input) as one call, with the same rules on every part:
the name is never cleaned, so " claim-1 " and "claim-1" derive different ids. For
verifying a stored id against the record's natural key, and for checking that another
system derived the id the same way.
CkUuid.IsFromName(
input: "2ed6657d-e927-568b-95e1-2665a8aea6a2",
name: "www.example.com",
space: CkUuid.NamespaceDns
); // -> true
CkUuid.IsFromName(
input: "2ed6657d-e927-568b-95e1-2665a8aea6a2",
name: "WWW.EXAMPLE.COM",
space: CkUuid.NamespaceDns
); // -> false (the name is hashed as given)
SameUuid
The same id, whatever the dressing?
bool SameUuid(
object? a = null,
object? b = null,
bool treatZerosAsMissing = true,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
a |
object? |
null |
The first value: text in any shape, or a boxed Guid. |
b |
object? |
null |
The second value, read the same way. |
treatZerosAsMissing |
bool |
true |
Counts the all-zeros UUID as missing, so two missing ids are not the same id. Switch it off to let two nil values match. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says which value is not a UUID and why, instead of answering false. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| Both read as UUIDs and are equal | true |
true |
| Both read, and differ | false |
false |
| Rejected: either value is not a UUID | false |
Throws CkUuidException — carries Input, Expected and Reason |
{08D3F9C6-…} from a SQL Server tool, the bare digits from a URL and a boxed Guid off
a reader all match one another. Two values that are not UUIDs are never the same — two
rejected values are two unknowns, not one identity — and by default neither are two nil
values, since missing is not an identity.
CkUuid.SameUuid("{08D3F9C6-5E4A-4B8F-9D2E-7A1B3C5D7E9F}", "08d3f9c65e4a4b8f9d2e7a1b3c5d7e9f"); // -> true
CkUuid.SameUuid(Guid.Empty, "00000000-0000-0000-0000-000000000000"); // -> false (two missing)
NewV7
An id that sorts by time.
Guid NewV7(
object? at = null,
bool throwIfInvalid = CkSettings.DefaultThrowIfInvalid
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
at |
object? |
null |
The moment to stamp, read as CkDateTime.ToDateTime reads one; null for now. |
throwIfInvalid |
bool |
CkSettings.DefaultThrowIfInvalid (false) |
Pass true to throw a CkUuidException that says why, instead of answering Guid.Empty, when at is not a date or lies before 1970, the epoch the id counts from. |
Returns
| When | Default | With throwIfInvalid: true |
|---|---|---|
| No moment, or a readable one | A new RFC 9562 version 7 UUID | The UUID |
Rejected: at unreadable or out of range |
Guid.Empty |
Throws CkUuidException — carries Input, Expected and Reason |
The moment sits in the first 48 bits and random bits follow, so ids made in sequence sort
in sequence — what a database index wants, and what Guid.NewGuid()'s random version 4
does not give it. Pin at in tests and for back-dated records.
Guid id = CkUuid.NewV7(); // now
Guid old = CkUuid.NewV7(at: "2026-08-31T14:05:00Z"); // sorts before id
Explain
Why not — in words, without an exception.
string Explain(
object? input = null,
bool treatZerosAsMissing = true
)
| Parameter | Type | Default | What it does |
|---|---|---|---|
input |
object? |
null |
The value: text in any everyday shape, or a boxed Guid. |
treatZerosAsMissing |
bool |
true |
Counts the all-zeros UUID as missing. |
Returns
| When | You get |
|---|---|
| The value passes the reader | "" |
| It does not | The reason, the same words the exception would carry — an answer, not a failure; it never throws |
The form-friendly twin of throwIfInvalid: the message to show beside the field,
without a try and catch. Every class with a reader has one, on the reader's own
rules, so the reason is exactly what the reader would say.
CkUuid.Explain("junk"); // -> "not a UUID in a known shape"
CkUuid.Explain("00000000-0000-0000-0000-000000000000"); // -> "the all-zeros UUID that means missing"
Good to know
ToGuidhas nofallbackparameter — on purpose. An identifier names one specific thing; an invented identity is worse than none. Rejection is alwaysGuid.Empty, so you can catch it — never a made-up id that quietly corrupts deduplication.- All zeros means missing, by default.
00000000-0000-0000-0000-000000000000is what databases and serializers emit when nobody set a value — the 1900-01-01 of identifiers. Every reader takestreatZerosAsMissing(defaulttrue) exceptVersion,IsStandardandIsVersion, which always count zeros as missing;ToGuidOrNullturns that missing value into an honestnull, andIsNilis the one method that answerstrueto it. - The validators answer
false, neverGuid.Empty.IsUuid,IsNil,IsCanonical,IsStandard,IsVersion,IsFromNameandSameUuidanswerfalseboth for "no" and for "not a UUID"; passthrowIfInvalid: truewhen the difference matters.IsVersionnever takes the flag. IsCanonicaljudges the shape,Canonicalreads any.IsCanonical("{…}")isfalsewhileCanonical("{…}")reads it fine. Use the validator where a field must already hold canonical text; use the reader everywhere else.- With the default on,
Guid.Emptyis an unambiguous signal. No valid read can produce it, soresult == Guid.Emptyreliably means "rejected". TurntreatZerosAsMissingoff and that signal becomes ambiguous — preferCanonicaland its""there. - Four shapes in, plus the
urn:uuid:prefix. Bare digits, hyphenated, braced, parenthesized, any casing. The exotic hex-struct"X"form ({0x08d3f9c6,0x5e4a,...}) is source code, not data, and is rejected — in reading and as aFormatshape. FromNamenever cleans the name." Claim-1 "and"claim-1"derive different UUIDs; normalise the name yourself, consistently, before deriving.- A boxed
Guidreads directly. Values coming off a database reader asobjectgo straight in — no.ToString()needed. CkDictionary uses the same reading forToGuidon payload bags, and CkSentinel applies the same all-zeros verdict on the way to storage. - Non-empty in, empty out means rejected for
CanonicalandFormat— the standard CommonKit signal (see How it works).
If you want errors instead
Pass throwIfInvalid: true and a value that cannot be used raises a
CkUuidException (from SafeCoder.CommonKit.Exceptions) instead of returning the
rejection value. The exception carries the Input, what was Expected and a short
Reason, flattened into a one-line message.
CkUuid.ToGuid(
input: "junk",
throwIfInvalid: true
); // throws CkUuidException — the message says why
ToGuidOrNull has no throwIfInvalid parameter and never throws — null is its
answer for anything unusable. When a bad value should be an error, read it with
ToGuid and the flag instead.