This project is no longer maintained. Its functionality has been moved to ktsu.Semantics.
Please migrate to the new library for continued support and updates.
A transparent wrapper for strings providing strong typing, compile-time feedback, and runtime validation
SemanticString provides a transparent wrapper around system strings to give you strong typing, compile time feedback, and runtime validation. It allows you to provide usage context and validation to naked strings in a similar way that Enums do for integers, making your code more type-safe and self-documenting.
- Strong Typing: Create domain-specific string types to prevent type confusion
- Compile-time Safety: Catch type mismatches at compile time rather than runtime
- Runtime Validation: Add custom validation rules to ensure strings meet your requirements
- Seamless Integration: Works naturally with existing string methods and APIs
- Zero-overhead: Designed for minimal performance impact when using validated strings
Install-Package ktsu.SemanticStringdotnet add package ktsu.SemanticString<PackageReference Include="ktsu.SemanticString" Version="x.y.z" />using ktsu.Semantics;
// Create a strong type by deriving a record class from SemanticString<TDerived>:
public record class MyStrongString : SemanticString<MyStrongString> { }
// Use the strong type in your code
public void ProcessData(MyStrongString data)
{
// Strong typing ensures you can't pass just any string here
Console.WriteLine(data);
}
// Create an instance
MyStrongString strongString = (MyStrongString)"Hello world";public class MyDemoClass
{
public MyStrongString Stronk { get; set; } = new();
public static void Demo(MyStrongString inStrongString, string inSystemString, out MyStrongString outStrongString, out string outSystemString)
{
// You can implicitly cast down to a System.String
outSystemString = inStrongString;
// You must explicitly cast up to a StrongString
outStrongString = (MyStrongString)inSystemString;
// You can provide a StrongString to a method that expects a System.String
Path.Combine(inStrongString, inSystemString);
// You can use the .WeakString property or .ToString() method to get the underlying System.String
outSystemString = inStrongString.WeakString;
outSystemString = inStrongString.ToString();
}
}You can provide custom validators which will throw a FormatException at runtime to help you catch data errors:
// Create validator classes by implementing ISemanticStringValidator
public abstract class StartsWithHttp : ISemanticStringValidator
{
public static bool IsValid(SemanticString? semanticString)
{
ArgumentNullException.ThrowIfNull(semanticString);
return semanticString.StartsWith("http", StringComparison.InvariantCultureIgnoreCase);
}
}
public abstract class EndsWithDotCom : ISemanticStringValidator
{
public static bool IsValid(SemanticString? semanticString)
{
ArgumentNullException.ThrowIfNull(semanticString);
return semanticString.EndsWith(".com", StringComparison.InvariantCultureIgnoreCase);
}
}
// Apply multiple validators to a semantic string type
public record class MyValidatedString : SemanticString<MyValidatedString, StartsWithHttp, EndsWithDotCom> { }
// This will pass validation
MyValidatedString valid = (MyValidatedString)"http://example.com";
// This will throw a FormatException
MyValidatedString invalid = (MyValidatedString)"example.org"; // Throws exception: doesn't end with .comFor more complex validation scenarios, you can combine multiple validators:
// Email validator
public abstract class EmailValidator : ISemanticStringValidator
{
public static bool IsValid(SemanticString? semanticString)
{
ArgumentNullException.ThrowIfNull(semanticString);
try
{
var addr = new System.Net.Mail.MailAddress(semanticString);
return addr.Address == semanticString;
}
catch
{
return false;
}
}
}
public record class EmailAddress : SemanticString<EmailAddress, EmailValidator> { }SemanticString is the successor to StrongStrings and provides improved functionality while maintaining compatibility with StrongStrings' core features. This section provides guidance for migrating from StrongStrings to SemanticString.
- Namespace Change: SemanticString uses
ktsu.Semanticsnamespace instead ofktsu.StrongStrings. - Validator Approach: SemanticString supports both:
- Interface-based validation (
ISemanticStringValidator) - Attribute-based validation (same as StrongStrings)
- Interface-based validation (
- Modern Features: SemanticString adds support for
ReadOnlySpan<char>and other modern C# features.
Update your class definitions to use SemanticString instead of StrongString:
// Old (StrongStrings)
using ktsu.StrongStrings;
public record MyString : StrongString<MyString> { }
// New (SemanticString)
using ktsu.Semantics;
public record MyString : SemanticString<MyString> { }The compatibility layer provides aliases to make migration easier:
// Use the aliases namespace for a smooth transition
using ktsu.StrongStrings.Aliases;
// This class is actually using SemanticString under the hood, but with
// StrongString compatible naming
public record MyString : StrongString<MyString> { }SemanticString fully supports the attribute-based validation pattern from StrongStrings:
// Attribute-based validation works the same way in SemanticString
[StartsWith("http://")]
[EndsWith(".com")]
public record MyUrl : SemanticString<MyUrl> { }All validation attributes from StrongStrings have been ported:
[StartsWith],[EndsWith],[Contains][RegexMatch],[PrefixAndSuffix][ValidateAll],[ValidateAny]for logical combinations
In addition to attribute-based validation, SemanticString also supports interface-based validators:
// Define a validator
public abstract class HttpValidator : ISemanticStringValidator
{
public static bool IsValid(ISemanticString? semanticString)
{
return semanticString?.StartsWith("http", StringComparison.OrdinalIgnoreCase) ?? false;
}
}
// Use the validator with generics
public record MyUrl : SemanticString<MyUrl, HttpValidator> { }Base class for creating semantic string types without validation.
| Name | Type | Description |
|---|---|---|
WeakString |
string |
The underlying string value |
| Name | Return Type | Description |
|---|---|---|
ToString() |
string |
Returns the underlying string value |
Equals(object?) |
bool |
Determines whether the specified object is equal to the current object |
GetHashCode() |
int |
Returns the hash code for this instance |
TryParse(string?, out TDerived?) |
bool |
Attempts to parse a string into a SemanticString of type TDerived |
Base class for creating semantic string types with one or more validators.
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE.md file for details.