A comprehensive .NET library for creating type-safe, validated types with semantic meaning. Transform primitive string and numeric obsession into strongly-typed, self-validating domain models with comprehensive validation, specialized path handling, and a complete physics quantities system covering 80+ quantities across 8 major scientific domains with dimensional analysis and centralized physical constants.
The Semantics library enables you to create strongly-typed wrappers that carry semantic meaning and built-in validation. Instead of passing raw primitives around your application, you can create specific types like EmailAddress, FilePath, Temperature, or UserId that are impossible to misuse and automatically validate their content.
- Type Safety: Eliminate primitive obsession with strongly-typed wrappers
- Comprehensive Validation: 50+ built-in validation attributes for all common scenarios
- Path Handling: Specialized path types with polymorphic interfaces and file system operations
- Complete Physics System: 80+ physics quantities across 8 scientific domains with dimensional analysis
- Physical Constants: Centralized, type-safe access to fundamental and derived constants with validation
- Bootstrap Architecture: Clean circular dependency resolution for complex type systems
- Unit Conversions: Automatic unit handling with compile-time dimensional safety
- Factory Pattern: Clean object creation with dependency injection support
- Performance Optimized: Span-based operations, pooled builders, and minimal allocations
- Enterprise Ready: Full .NET ecosystem integration (ASP.NET Core, Entity Framework, etc.)
- Comprehensive Testing: Derived constants validation and physics relationship verification
dotnet add package ktsu.Semanticsusingktsu.Semantics;// Define strongly-typed domain models[IsEmail]publicsealedrecordEmailAddress:SemanticString<EmailAddress>{}[HasLength(8,50),IsNotEmpty]publicsealedrecordUserId:SemanticString<UserId>{}// Simple direct usage - Clean API with type inference:// 1. Create methods (recommended) - no generic parameters needed!varemail1=EmailAddress.Create("user@example.com");varuserId1=UserId.Create("USER_12345");// 2. From character arrayschar[]emailChars=['u','s','e','r','@','e','x','a','m','p','l','e','.','c','o','m'];varemail2=EmailAddress.Create(emailChars);// 3. From ReadOnlySpan<char> (performance optimized)varuserId2=UserId.Create("USER_12345".AsSpan());// 4. Explicit string castingvaremail3=(EmailAddress)"user@example.com";varuserId3=(UserId)"USER_12345";// 5. Safe creation with TryCreate (no exceptions)if(EmailAddress.TryCreate("maybe@invalid",outEmailAddress?safeEmail)){// Use safeEmail - validation succeeded}// Compile-time safety prevents mistakespublicvoidSendWelcomeEmail(EmailAddressto,UserIduserId){/* ... */}// This won't compile - type safety in action!// SendWelcomeEmail(userId, email); // ❌ Compiler error!// Use factory pattern (recommended for dependency injection)varemailFactory=newSemanticStringFactory<EmailAddress>();varuserFactory=newSemanticStringFactory<UserId>();// Clean overloaded API - Create methodsvaremail=emailFactory.Create("user@example.com");varuserId=userFactory.Create("USER_12345");// All input types supported via overloadingvaremail2=emailFactory.Create(['u','s','e','r','@','e','x','a','m','p','l','e','.','c','o','m']);varuserId2=userFactory.Create("USER_12345".AsSpan());// Safe creation with TryCreateif(emailFactory.TryCreate("maybe@invalid",outEmailAddress?safeEmail)){// Success!}// Legacy FromString methods still available varemail3=emailFactory.FromString("user@example.com");// Complete physics system with 80+ quantities across 8 domainspublicsealedrecordTemperature<T>:PhysicalQuantity<Temperature<T>,T>whereT:struct,INumber<T>{}publicsealedrecordForce<T>:PhysicalQuantity<Force<T>,T>whereT:struct,INumber<T>{}publicsealedrecordEnergy<T>:PhysicalQuantity<Energy<T>,T>whereT:struct,INumber<T>{}// Create quantities with dimensional safetyvartemp=Temperature<double>.FromCelsius(25.0);// 298.15 Kvarforce=Force<double>.FromNewtons(100.0);// 100 Nvardistance=Length<double>.FromMeters(5.0);// 5 m// Physics relationships with compile-time safetyvarwork=force*distance;// Results in Energy<double>varpower=work/Time<double>.FromSeconds(10.0);// Results in Power<double>// Type-safe unit conversionsConsole.WriteLine(temp.ToFahrenheit());// 77°FConsole.WriteLine(force.ToPounds());// 22.48 lbf// Access physical constants with type safetyvargasConstant=PhysicalConstants.Generic.GasConstant<double>();// 8.314 J/(mol·K)varspeedOfLight=PhysicalConstants.Generic.SpeedOfLight<float>();// 299,792,458 m/svarplanckConstant=PhysicalConstants.Generic.PlanckConstant<decimal>();// Type-safe constant access// Dimensional analysis prevents errors// var invalid = force + temp; // ❌ Compiler error!// Use specialized path typesvarfileFactory=newSemanticStringFactory<AbsoluteFilePath>();varconfigFile=fileFactory.Create(@"C:\app\config.json");// Rich path operationsConsole.WriteLine(configFile.FileName);// config.jsonConsole.WriteLine(configFile.FileExtension);// .json Console.WriteLine(configFile.DirectoryPath);// C:\appConsole.WriteLine(configFile.Exists);// True/False// Polymorphic path collectionsList<IPath>allPaths=[AbsoluteFilePath.FromString<AbsoluteFilePath>(@"C:\data.txt"),RelativeDirectoryPath.FromString<RelativeDirectoryPath>(@"logs\app"),FilePath.FromString<FilePath>(@"document.pdf")];// Filter by interface typevarfilePaths=allPaths.OfType<IFilePath>().ToList();varabsolutePaths=allPaths.OfType<IAbsolutePath>().ToList();// Combine multiple validation rules[IsNotEmpty,IsEmail,HasLength(5,100)]publicsealedrecordBusinessEmail:SemanticString<BusinessEmail>{}// Use validation strategies for flexible requirements[ValidateAny]// Either email OR phone is acceptable[IsEmail,RegexMatch(@"^\+?\d{10,15}$")]publicsealedrecordContactInfo:SemanticString<ContactInfo>{}// First-class type validation[IsDateTime]publicsealedrecordScheduledDate:SemanticString<ScheduledDate>{}[IsDecimal,IsPositive]publicsealedrecordPrice:SemanticString<Price>{}[IsGuid]publicsealedrecordTransactionId:SemanticString<TransactionId>{}[HasLength(3,20),IsNotEmpty]publicsealedrecordProductSku:SemanticString<ProductSku>{}[IsPositive,IsDecimal]publicsealedrecordPrice:SemanticString<Price>{}[IsEmail]publicsealedrecordCustomerEmail:SemanticString<CustomerEmail>{}publicclassOrder{publicCustomerEmailCustomerEmail{get;set;}publicProductSku[]Items{get;set;}publicPriceTotalAmount{get;set;}}[IsAbsolutePath,DoesExist]publicsealedrecordConfigFilePath:SemanticString<ConfigFilePath>{}[IsIpAddress]publicsealedrecordServerAddress:SemanticString<ServerAddress>{}[IsInRange(1,65535)]publicsealedrecordPort:SemanticQuantity<Port,int>{}All physical constants are centralized in PhysicalConstants with type-safe generic access:
// Fundamental constants (SI 2019 definitions)varc=PhysicalConstants.Generic.SpeedOfLight<double>();// 299,792,458 m/svarh=PhysicalConstants.Generic.PlanckConstant<double>();// 6.62607015×10⁻³⁴ J⋅svark=PhysicalConstants.Generic.BoltzmannConstant<double>();// 1.380649×10⁻²³ J/KvarNA=PhysicalConstants.Generic.AvogadroNumber<double>();// 6.02214076×10²³ /mol// Temperature constantsvarT0=PhysicalConstants.Generic.StandardTemperature<double>();// 273.15 KvarP0=PhysicalConstants.Generic.StandardAtmosphericPressure<double>();// 101,325 Pa// Conversion factors with derived validationvarftToM=PhysicalConstants.Generic.FeetToMeters<double>();// 0.3048 m/ftvarsqFtToSqM=PhysicalConstants.Generic.SquareFeetToSquareMeters<double>();// Derived: ftToM²// All constants have comprehensive test coverage ensuring derived values match calculationsThe library includes 80+ physics quantities across 8 scientific domains:
// Kinematics and dynamicsvarvelocity=Velocity<double>.FromMetersPerSecond(15.0);varacceleration=Acceleration<double>.FromMetersPerSecondSquared(9.8);varforce=Mass<double>.FromKilograms(10.0)*acceleration;// F = ma// Work and energyvarwork=force*Length<double>.FromMeters(5.0);// W = F⋅dvarpower=work/Time<double>.FromSeconds(2.0);// P = W/t// Ohm's law relationshipsvarvoltage=Voltage<double>.FromVolts(12.0);varcurrent=Current<double>.FromAmperes(2.0);varresistance=voltage/current;// R = V/Ivarpower=voltage*current;// P = VI// Thermodynamicsvartemp=Temperature<double>.FromCelsius(25.0);varheat=Heat<double>.FromJoules(1000.0);varcapacity=HeatCapacity<double>.FromJoulesPerKelvin(100.0);varentropy=heat/temp;// S = Q/T// Chemical calculationsvarmoles=AmountOfSubstance<double>.FromMoles(0.5);varmolarity=moles/Volume<double>.FromLiters(2.0);// M = n/Vvarrate=ReactionRate<double>.FromMolarPerSecond(0.01);// Sound and vibrationvarfrequency=Frequency<double>.FromHertz(440.0);// A4 notevarwavelength=SoundSpeed<double>.Default/frequency;// λ = v/f varintensity=SoundIntensity<double>.FromWattsPerSquareMeter(1e-6);// Nuclear physicsvaractivity=RadioactiveActivity<double>.FromBecquerels(1000.0);vardose=AbsorbedDose<double>.FromGrays(0.001);varexposure=Exposure<double>.FromCoulombsPerKilogram(1e-6);// Photometry and opticsvarflux=LuminousFlux<double>.FromLumens(800.0);varilluminance=flux/Area<double>.FromSquareMeters(4.0);// E = Φ/Avarluminance=Luminance<double>.FromCandelasPerSquareMeter(100.0);// Fluid mechanicsvarviscosity=DynamicViscosity<double>.FromPascalSeconds(0.001);varflowRate=VolumetricFlowRate<double>.FromCubicMetersPerSecond(0.1);varreynolds=ReynoldsNumber<double>.Calculate(velocity,Length<double>.FromMeters(0.1),viscosity);The library uses a sophisticated bootstrap architecture to resolve circular dependencies:
// BootstrapUnits class provides initial unit definitions during system initialization// PhysicalDimensions uses BootstrapUnits to define dimensions without circular dependencies// Units class replaces bootstrap units with full unit definitions after initialization// This clean separation enables complex type systems while maintaining performanceAll derived physical constants are validated against their fundamental relationships:
// Example: Area conversions are validated to ensure SquareFeetToSquareMeters = FeetToMeters²[TestMethod]publicvoidDerivedConstants_AreaConversions_MatchCalculatedValues(){varfeetToMeters=PhysicalConstants.Conversion.FeetToMeters;varcalculatedSquareFeet=feetToMeters*feetToMeters;varstoredSquareFeet=PhysicalConstants.Conversion.SquareFeetToSquareMeters;Assert.AreEqual(calculatedSquareFeet,storedSquareFeet,tolerance);}// Comprehensive test coverage ensures physical relationships are mathematically correct// Register factories in your DI containerservices.AddTransient<ISemanticStringFactory<EmailAddress>,SemanticStringFactory<EmailAddress>>();// Use in servicespublicclassUserService{privatereadonlyISemanticStringFactory<EmailAddress>_emailFactory;publicUserService(ISemanticStringFactory<EmailAddress>emailFactory){_emailFactory=emailFactory;}publicasyncTask<User>CreateUserAsync(stringemail){// Factory handles validation and throws meaningful exceptionsvarvalidatedEmail=_emailFactory.Create(email);returnnewUser(validatedEmail);}}Comprehensive documentation is available in the docs/ directory:
- Complete Library Guide - 🌟 START HERE - Complete overview of all library features and components
- Architecture Guide - SOLID principles, design patterns, and system architecture
- Advanced Usage Guide - Advanced features, custom validation, and best practices
- Validation Reference - Complete reference of all validation attributes
- FluentValidation Integration - Integration with FluentValidation library
Extensive examples are available in docs/examples/:
- Getting Started - Basic usage patterns
- Physics Relationships - Physics calculations and relationships
- Validation Attributes - Built-in and custom validation
- Path Handling - File system operations
- Factory Pattern - Object creation and DI
- String Operations - String compatibility and LINQ
- Type Conversions - Cross-type conversions
- Real-World Scenarios - Complete domain examples
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE.md file for details.
Transform your primitive-obsessed code into a strongly-typed, self-validating domain model with ktsu.Semantics.