Expert guidance for .NET library development with Smart Enums, Value Objects, and Discriminated Unions using Roslyn Source Generators
Expert guidance for working with the Thinktecture.Runtime.Extensions library - a .NET library providing Smart Enums, Value Objects, and Discriminated Unions through Roslyn Source Generators.
This skill helps you work with a sophisticated .NET library that uses source generators to eliminate boilerplate code for:
**`src/Thinktecture.Runtime.Extensions`**: Core library with base interfaces, attributes, and runtime helpers
**`src/Thinktecture.Runtime.Extensions.SourceGenerator`**: Contains 6 Roslyn Source Generators and 2 Analyzers:
Source Generators:
1. SmartEnumSourceGenerator - Factory methods, operators, Switch/Map for `[SmartEnum<T>]` or `[SmartEnum]`
2. ValueObjectSourceGenerator - Factory methods, equality, operators for `[ValueObject<T>]` or `[ComplexValueObject]`
3. AdHocUnionSourceGenerator - Conversion operators, Switch/Map for `[Union<T1, T2>]` or `[AdHocUnion(...)]`
4. RegularUnionSourceGenerator - Factory methods, Switch/Map for `[Union]` inheritance-based unions
5. ObjectFactorySourceGenerator - Custom serialization/parsing logic for `[ObjectFactory<T>]`
6. AnnotationsSourceGenerator - JetBrains annotations if not present
Analyzers:
1. ThinktectureRuntimeExtensionsAnalyzer - 40+ diagnostic rules validating correct usage
2. ThinktectureRuntimeExtensionsInternalUsageAnalyzer - Prevents usage of internal library APIs
**Framework Integration Projects**: Separate projects for JSON, MessagePack, Newtonsoft.Json, ProtoBuf, EF Core (8/9/10), ASP.NET Core, and Swashbuckle
Generated types implement `IMetadataOwner` interface with runtime metadata enabling:
The `MetadataLookup` class provides cached metadata discovery via reflection. Object factories have priority over key-based metadata for conversion scenarios.
**Keyless `[SmartEnum]`**: Type-safe enums without underlying values (items as public static readonly fields)
**Keyed `[SmartEnum<TKey>]`**: Type-safe enums with underlying key values (int, string, Guid, custom types)
**Simple `[ValueObject<TKey>]`**: Single-value immutable types (e.g., Amount, ProductId)
**Complex `[ComplexValueObject]`**: Multi-property immutable types (e.g., DateRange)
**Ad-hoc `[Union<T1, T2>]` or `[AdHocUnion(typeof(T1), typeof(T2))]`**: Simple 2-5 type combinations
**Regular `[Union]`**: Inheritance-based unions with derived types
When working with external libraries, frameworks, or APIs (including .NET BCL, ASP.NET Core, Entity Framework Core, serialization frameworks):
**NEVER guess or assume API behavior**
**Verify using Context7 MCP when needed**
1. Use `mcp__context7__resolve-library-id` to find the correct library ID
2. Use `mcp__context7__get-library-docs` to retrieve up-to-date, accurate documentation
3. Base all implementation decisions on verified documentation, not assumptions
**This project's code is authoritative**
**Verification over speed**
For larger tasks with multiple distinct steps, ALWAYS use specialized subagents to keep main context clean:
**Always delegate to subagents when:**
**Do NOT delegate simple tasks:**
**Example workflow for "Add feature X":**
1. User requests feature → Use `feature-implementation-planner` to create plan
2. Plan approved → Use `feature-implementer` to write code
3. Implementation complete → Use `feature-test-writer` to add tests
4. Tests passing → Use `documentation-updater` to update docs
5. All done → Use `feature-reviewer` for final review
Types must be `partial` classes/structs. Generator creates:
**Serialization**: System.Text.Json, MessagePack, Newtonsoft.Json, ProtoBuf - reference package for auto-generation or manually register converters
**Entity Framework Core**: Version-specific packages (8/9/10) - call `.UseThinktectureValueConverters()` on DbContextOptionsBuilder
**ASP.NET Core**: Model binding via `IParsable<T>` interface (auto-generated) - use `[ObjectFactory<string>]` for custom parsing
**Swashbuckle/OpenAPI**: Schema and operation filters for proper OpenAPI documentation
Add `partial` keyword to your class/struct declaration
Add `[KeyMemberEqualityComparer<MyType, string, StringComparer>]` attribute
Ensure items are public static readonly fields of the enum type
Ensure integration package is referenced, or manually register converters/formatters
Call `.UseThinktectureValueConverters()` on DbContextOptionsBuilder
Requires NET9+; ensure project targets `net9.0` or later and key type implements `ISpanParsable<TKey>`
1. **String-based keys/members**: Always explicitly specify equality comparer to avoid culture-sensitive comparisons
2. **Validation**: Prefer `ValidateFactoryArguments` over `ValidateConstructorArguments`
3. **Immutability**: All members should be readonly (fields) or have no setter/private init (properties)
4. **Constructors**: Keep constructors private to enforce use of factory methods
5. **Smart Enum items**: Must be public static readonly fields
6. **Partial keyword**: Types must be marked `partial` for source generators to work
7. **Culture-specific parsing**: Always pass appropriate `IFormatProvider` when parsing/formatting culture-sensitive types
8. **Arithmetic operators**: Use unchecked arithmetic context - overflow/underflow wraps around
When implementing features:
1. Consult specialized documentation files for detailed guidance
2. Follow the zero-hallucination policy for external APIs
3. Use task delegation for complex multi-step implementations
4. Maintain XML documentation for all public APIs
5. Write comprehensive tests using xUnit, Verify, and AwesomeAssertions
6. Follow code style defined in `.editorconfig`
7. Update `Directory.Packages.props` for any new package dependencies
8. Ensure multi-target framework compatibility where applicable
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/thinktectureruntimeextensions-development-assistant/raw