ktsu.Semantics.Strings 3.1.2

Prefix Reserved
dotnet add package ktsu.Semantics.Strings --version 3.1.2
                    
NuGet\Install-Package ktsu.Semantics.Strings -Version 3.1.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ktsu.Semantics.Strings" Version="3.1.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ktsu.Semantics.Strings" Version="3.1.2" />
                    
Directory.Packages.props
<PackageReference Include="ktsu.Semantics.Strings" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ktsu.Semantics.Strings --version 3.1.2
                    
#r "nuget: ktsu.Semantics.Strings, 3.1.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ktsu.Semantics.Strings@3.1.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ktsu.Semantics.Strings&version=3.1.2
                    
Install as a Cake Addin
#tool nuget:?package=ktsu.Semantics.Strings&version=3.1.2
                    
Install as a Cake Tool

ktsu.Semantics.Strings

Strongly-typed, self-validating string wrappers that replace primitive obsession with compile-time-safe domain types.

License NuGet Version NuGet Version NuGet Downloads GitHub commit activity GitHub contributors GitHub Actions Workflow Status

ktsu.Semantics.Strings is one package in the ktsu.Semantics family. For the family overview and the other pillars (paths, quantities, music, color) start at the root README.

Introduction

ktsu.Semantics.Strings gives you a base type, SemanticString<TDerived>, for defining string-shaped domain types such as EmailAddress, UserId, or BlogSlug. A semantic string validates itself on construction, normalizes its value, carries the whole System.String surface, and is distinct from every other semantic type at compile time. An EmailAddress will not silently substitute for a UserId, so a whole class of "passed the arguments in the wrong order" bugs stops compiling.

Validation is declarative. You attach attributes such as [IsEmailAddress] or [StartsWith("USER_")] to the type, and the framework runs them whenever an instance is created. Ready-made identifier types (Uuid, Iban, Isbn, and more) live in the companion ktsu.Semantics.Strings.Identifiers package.

Features

  • SemanticString<TDerived> base type: an abstract record using the curiously-recurring template pattern, so derived types get value equality, ordering, and the full string API for free.

  • Validating factories: Create throws on invalid input, TryCreate returns a bool and never throws. Both accept string, char[], and ReadOnlySpan<char>.

  • Declarative validation attributes: casing, format, text, and first-class .NET type checks, combined with [ValidateAll] (default, logical AND) or [ValidateAny] (logical OR).

  • Normalization hook: override MakeCanonical to trim, case-fold, or otherwise canonicalize a value before validation runs.

  • Fluent conversions: "user@example.com".As<EmailAddress>() and cross-type reinterpretation via source.As<TSource, TTarget>().

  • Factory abstraction for dependency injection: ISemanticStringFactory<T> / SemanticStringFactory<T> for constructor injection, with a SemanticStringFactory<T>.Default singleton for non-DI use.

  • Span-friendly and allocation-conscious: span-based overloads and a ref struct split enumerator on the target frameworks that support them.

  • Dependency-free: no NuGet dependencies on .NET 8 and later.

  • JSON round-trip serialization: opt-in. A semantic string is an IEnumerable<char>, so System.Text.Json writes it as an array of characters unless you register a converter. Add one that writes ToString() and reads back through Create<T>(string)ktsu.RoundTripStringJsonConverter supplies a suitable factory:

    JsonSerializerOptions options = new()
    {
        Converters = { new RoundTripStringJsonConverterFactory() },
    };
    

Installation

Package Manager Console

Install-Package ktsu.Semantics.Strings

.NET CLI

dotnet add package ktsu.Semantics.Strings

Package Reference

<PackageReference Include="ktsu.Semantics.Strings" Version="x.y.z" />

Usage Examples

Basic Example

using ktsu.Semantics.Strings;

[IsEmailAddress]
public sealed record EmailAddress : SemanticString<EmailAddress> { }

[StartsWith("USER_"), HasNonWhitespaceContent]
public sealed record UserId : SemanticString<UserId> { }

// Direct construction, no generic argument needed
EmailAddress email = EmailAddress.Create("user@example.com");
UserId userId = UserId.Create("USER_12345");

// Safe creation, no exception on failure
if (EmailAddress.TryCreate("maybe@invalid", out EmailAddress? safe))
{
    // use safe
}

// Compile-time safety
public void SendWelcomeEmail(EmailAddress to, UserId who) { /* ... */ }
// SendWelcomeEmail(userId, email);   // does not compile

A semantic string converts implicitly to string, so it drops into any API that expects one. Construction is always explicit (Create / As), which guarantees validation runs.

Combining attributes

// All attributes must pass (default behavior)
[IsEmailAddress, EndsWith(".com")]
public sealed record DotComEmail : SemanticString<DotComEmail> { }

// Any one attribute passing is sufficient
[ValidateAny]
[IsEmailAddress, StartsWith("https://")]
public sealed record ContactMethod : SemanticString<ContactMethod> { }

The parameterized text attributes (Contains, StartsWith, EndsWith, PrefixAndSuffix, RegexMatch) allow multiples, so you can stack several and combine them with [ValidateAny].

Normalization before validation

using ktsu.Semantics.Strings;

[HasNonWhitespaceContent]
public sealed record Slug : SemanticString<Slug>
{
    protected override string MakeCanonical(string input) =>
        input.Trim().ToLowerInvariant().Replace(' ', '-');
}

Slug slug = Slug.Create("  Hello World  ");   // stored as "hello-world"

Dependency injection

The package ships no AddSemanticStrings() helper. Register each closed factory type you need:

services.AddScoped<ISemanticStringFactory<EmailAddress>, SemanticStringFactory<EmailAddress>>();

public class UserService(ISemanticStringFactory<EmailAddress> emails)
{
    public User CreateUser(string raw) =>
        emails.TryFromString(raw, out EmailAddress? email)
            ? new User(email!)
            : throw new ArgumentException("invalid email");
}

For code that is not using a container, SemanticStringFactory<EmailAddress>.Default is a ready singleton.

API Reference

SemanticString<TDerived>

Abstract base record for all semantic string types. TDerived is the concrete type itself.

Key members
Name Signature Description
WeakString string { get; init; } The underlying raw value.
Length int { get; } Length of the underlying string.
Create static TDerived Create(string?) (also char[], ReadOnlySpan<char>) Validates and constructs. Throws ArgumentException on invalid input, ArgumentNullException on null.
TryCreate static bool TryCreate(string?, out TDerived?) (also char[], ReadOnlySpan<char>) Returns false instead of throwing.
As<TDest>() TDest As<TDest>() Reinterprets the value as another semantic type, re-validating against its rules.
MakeCanonical protected virtual string MakeCanonical(string) Normalization hook run before validation.
IsValid virtual bool IsValid() True when the value is non-null and passes attribute validation.
WithPrefix / WithSuffix TDerived WithPrefix(string) / TDerived WithSuffix(string) Type-safe prefix/suffix transforms.
implicit string implicit operator string(SemanticString<TDerived>?) Converts to string (null becomes string.Empty).
<, <=, >, >=, CompareTo ordering members Ordinal comparison on the underlying string.

The base also forwards the common System.String surface (Contains, IndexOf, Substring, Split, Trim, StartsWith, EndsWith, casing helpers, and more) plus span-based helpers on the target frameworks that support them.

ISemanticStringFactory<T> / SemanticStringFactory<T>

Name Return Type Description
FromString(string?) T Creates an instance, throwing on invalid input.
FromCharArray(char[]?) T As above from a char array.
TryFromString(string?, out T?) bool Non-throwing creation.
SemanticStringFactory<T>.Default SemanticStringFactory<T> Shared singleton for non-DI use.

Validation attributes

All attributes apply to a class, derive from SemanticStringValidationAttribute, and live in the ktsu.Semantics.Strings namespace.

Category Representative attributes
Casing IsCamelCase, IsPascalCase, IsSnakeCase, IsKebabCase, IsMacroCase, IsTitleCase, IsSentenceCase, IsUpperCase, IsLowerCase
Format HasNonWhitespaceContent, IsSingleLine, IsMultiLine, HasMinimumLines(n), HasMaximumLines(n), HasExactLines(n), IsEmptyOrWhitespace
Text Contains(substring), StartsWith(prefix), EndsWith(suffix), PrefixAndSuffix(prefix, suffix), RegexMatch(pattern), IsBase64, IsEmailAddress
Combination markers [ValidateAll] (default), [ValidateAny]

The full catalogue lives in the validation reference.

Architecture

Validation is a small strategy/adapter/rule pipeline. A combination strategy (ValidateAllStrategy / ValidateAnyStrategy, chosen by ValidationStrategyFactory) decides whether a type's attributes are combined with AND or OR. Each attribute delegates to a ValidationAdapter that returns a ValidationResult. A separate rule abstraction (IValidationRule, ValidationRuleBase) provides an open extension point for adding named, prioritized rules without touching existing code. See the architecture guide for the full picture.

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.

License

This project is licensed under the MIT License. See the LICENSE.md file for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (25)

Showing the top 5 NuGet packages that depend on ktsu.Semantics.Strings:

Package Downloads
ktsu.AppDataStorage

A .NET library for persistent application data storage using JSON serialization. Provides a simple inherit-and-use pattern with automatic file management, thread-safe operations, debounced saves, backup recovery, and singleton access. Stores data in the user's app data folder with support for custom subdirectories and file names.

ktsu.Semantics.Paths

A comprehensive .NET library for replacing primitive obsession with strongly-typed, self-validating domain models across four pillars: semantic strings with 50+ validation attributes, polymorphic path handling, metadata-generated semantic quantities, and musical value types. The quantity system covers 60+ physical dimensions and 200+ generated types under a unified vector model, with compile-time dimensional safety, generated unit conversions and physics relationships, centralized physical constants, and optional per-storage-type alias packages. The music types provide type-safe pitches, intervals, scales and modes, chords with symbol parsing and voicing, keys with roman-numeral analysis, and rational durations and time signatures. Features factory-pattern and dependency-injection support for building robust, maintainable scientific and domain-specific applications.

ktsu.CredentialCache

A cross-platform credential cache for .NET that keeps secrets in memory for fast process-lifetime lookup and persists each one through the host's native keyring: Windows Credential Manager, macOS Keychain Services, or the freedesktop.org Secret Service on Linux. Every credential is stored as its own keyring entry scoped by a service name, so no plaintext blob is ever written to disk, and a pluggable ICredentialStore lets you substitute an in-memory store or your own backend.

ktsu.ImGuiCredentialPopups

A .NET library providing ready-made Dear ImGui modal dialogs for collecting credentials. Ships username/password and token popups built on a shared CredentialPopup base, with masked input, automatic keyboard focus, and confirmation callbacks that hand back a ktsu.CredentialCache credential ready to store or use.

ktsu.ImGui.Popups

A professional library for modal dialogs and popup components in ImGui.NET, providing message boxes, input prompts with validation (string, int, float), searchable selection lists with type-safe generics, and an advanced filesystem browser with open/save modes, directory navigation, and pattern filtering support.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.1.2 41 8/21/2026
3.1.1 507 8/19/2026
3.1.0 319 8/19/2026
3.0.1 588 8/18/2026
3.0.0 1,108 8/15/2026
2.9.14 1,052 8/14/2026
2.9.13 172 8/14/2026
2.9.12 167 8/14/2026
2.9.11 363 8/14/2026
2.9.10 314 8/14/2026
2.9.9 156 8/14/2026
2.9.8 153 8/14/2026
2.9.7 185 8/14/2026
2.9.6 182 8/14/2026
2.9.5 164 8/14/2026
2.9.4 160 8/14/2026
2.9.3 1,226 8/7/2026
2.9.2 203 8/6/2026
2.9.1 410 8/5/2026
2.9.0 505 8/4/2026
Loading failed

## v3.1.2 (patch)

Changes since v3.1.1:

- Bump the ktsu group with 11 updates ([@dependabot[bot]](https://github.com/dependabot[bot]))
- Bump the ktsu group with 9 updates ([@dependabot[bot]](https://github.com/dependabot[bot]))