Conversion Mechanisms
Overview
When converting between value objects and other types, you have several options with different tradeoffs. Understanding when to use each mechanism ensures your code is both type-safe and maintainable.
Quick Reference Matrix
Mechanism | Best For | Type Safety | Framework Friendly | Performance | Validation |
|---|---|---|---|---|---|
IConvertible | Dynamic runtime conversion | ⭐⭐ | Yes (LINQ-to-SQL, ORMs) | ⭐⭐ | N/A |
Explicit Cast | Domain logic, explicit intent | ⭐⭐⭐ | Limited | ⭐⭐⭐ | Yes |
Implicit Cast | ⚠️ Not recommended | ⭐ | Limited | ⭐⭐⭐ | No |
TypeConverter | Framework binding, ASP.NET routes | ⭐⭐ | ⭐⭐⭐ | ⭐⭐ | Yes |
JSON (STJ/NSJ) | API serialization | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | Yes |
EF Core Converter | Database persistence | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | Via converter |
BSON/MessagePack | Format-specific serialization | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | Yes |
IConvertible – Dynamic Runtime Conversion
For detailed information, see IConvertible
When to Use IConvertible
Use IConvertible when:
You need dynamic type conversion with the target type determined at runtime
Integrating with frameworks that expect
IConvertible(some ORMs, reflection utilities)You need
Convert.ChangeType()to work seamlessly with your value objectsWorking with legacy code that relies on runtime type conversion
When NOT to Use
Avoid relying solely on IConvertible when:
You need compile-time type safety (prefer explicit casting)
The conversion requires validation (prefer TypeConverter or explicit methods)
You want clear intent in your code (explicit methods are more readable)
Example: ORM Dynamic Mapping
Explicit Casting - Type-Safe Domain Logic
When to Use Casting
Use explicit casting when:
You need compile-time type safety with clear intent
Converting as part of domain logic (e.g.,
(int)customerId)You want to prevent accidental conversions between different value objects
Performance is critical and you're converting frequently
Configuration
Example: Domain Logic with Type Safety
Implicit Casting (⚠️ Not Recommended)
While you can enable implicit casting, it is not recommended because:
Reduces type safety - Conversions can happen accidentally
Violates implicit conversion rules -
implicitshould never throw, but value object conversion validatesAmbiguity between value objects -
implicit operator intmakes it unclear which value object you're converting
TypeConverter – Framework Integration
When to Use TypeConverters
Use TypeConverter when:
ASP.NET Core parameter binding in routes, query strings, or model binding
WPF data binding in XAML
Data grids that convert cell values to/from strings
Any framework that uses the .NET type conversion infrastructure
How It Works
Vogen generates a TypeConverter that:
Converts value objects to/from strings
Validates during conversion (respects your validation rules)
Integrates with ASP.NET Core's
[FromRoute],[FromQuery]attributesWorks with WPF bindings and other reflection-based frameworks
Example: ASP.NET Core Routes
Example: WPF Data Binding
JSON Serialization - API & Data Exchange
JSON serialization is handled through different converters based on your needs.
System.Text.Json (STJ) - Default & Recommended
Advantages:
Default (included automatically)
Native .NET support, excellent performance
AOT-friendly with source-generated factories
Serializes primitive directly:
{"price": 99.99}instead of{"price": {"value": 99.99}}
Usage:
Newtonsoft.Json (JSON.NET) – Legacy Support
If you're using Newtonsoft.Json in your project:
When to choose:
You already depend on Newtonsoft.Json
You need specific Newtonsoft features or settings
Legacy projects that use JSON.NET extensively
JSON Schema Best Practice
Both STJ and Newtonsoft serialize the primitive directly, which is the correct design:
This approach:
✅ Matches schema expectations
✅ Provides clean API contracts
✅ Improves debuggability
✅ Reduces network payload
Database Integration
Entity Framework Core
When to use: Primary database persistence with EF Core.
Dapper
When to use: Lightweight micro-ORMs with manual SQL queries.
LINQ to DB
When to use: LINQ to DB data access layer.
Specialized Formats
BSON (MongoDB)
MessagePack
Orleans (Distributed Systems)
Decision Framework
When choosing a conversion mechanism, ask these questions in order:
Are you converting at API boundaries?
Yes → Use JSON serialization (STJ/Newtonsoft) or appropriate format (BSON, MessagePack)
No → Continue to #2
Is the conversion happening in domain logic?
Yes → Use explicit casting for type safety
No → Continue to #3
Does your framework need to convert?
ASP.NET Core routes/binding → Use TypeConverter
Database persistence → Use EF/Dapper/LINQ-to-DB converter
Dynamic/reflection-based → Use IConvertible
Continue to #4
Do you need dynamic runtime conversion?
Yes → Use IConvertible
No → Use explicit casting or custom methods
Advanced: Combining Mechanisms
You often use multiple mechanisms in the same application:
See Also
IConvertible – Detailed IConvertible documentation
Integration – Serialization and converter configuration
Hoisting – What interfaces and methods Vogen hoists
Casting Operators – Configuring cast operators