A high-performance, lightweight object-to-object mapper for .NET with zero dependencies. ValueMapper provides fast mapping capabilities with a simple API, making it easy to map between different object types while maintaining good performance.
Feature | ValueMapper | Mapster | AutoMapper |
---|---|---|---|
Zero Dependencies | β | β | β |
Basic Property Mapping | β | β | β |
Flattening | β | β | β |
Deep Object Mapping | β | β | β |
Collection Mapping | β | β | β |
Enum Mapping | β | β | β |
Custom Property Mapping | β (attr) | β | β |
Property Ignoring | β | β | β |
Type Conversion | β | β | β |
Nullable Handling | β | β | β |
Configuration API | β | β | β |
Custom Value Resolvers | β | β | β |
Conditional Mapping | β | β | β |
Circular Reference Handling | β | β | β |
Before/After Mapping Actions | β | β | β |
Runtime Configuration | β | β | β |
Mapping Validation | β | β | β |
Collection Type Conversion | β (ListβList only) | β | β |
Parallel Collection Mapping | β (built-in) | β+ | β+ |
Compile-time Type Safety | β | ββ‘ | ββ‘ |
Mapping Cache | β | β | β |
Performance (vs Manual)* | ~11.95x slower | ~8.11x slower | ~12.67x slower |
* Based on benchmark results for single object mapping. For collection mapping (100,000 items), ValueMapper performs better: ValueMapper (39.84ms), Mapster (65.34ms), AutoMapper (70.80ms).
- Can be implemented manually
- β¨ Zero dependencies
- π High performance
- π‘ Simple API
- π Automatic type conversion
- π·οΈ Custom property mapping via attributes
- βοΈ Property ignoring
- π Collection mapping
- π Enum mapping (case-insensitive)
- π§΅ Parallel collection mapping for large datasets
- π Thread-safe operation
- π₯ Mapping compilation caching
dotnet add package ValueMapper
var source = new Source
{
Name = "John Doe",
Age = 30,
City = "New York"
};
var destination = ValueMapper.Map<Source, Destination>(source);
public class Source
{
[ValueMapperMapping("CustomName")]
public string SourceProperty { get; set; }
}
public class Destination
{
public string CustomName { get; set; }
}
var source = new Source { SourceProperty = "Custom Value" };
var destination = ValueMapper.Map<Source, Destination>(source);
// destination.CustomName will contain "Custom Value"
public class Source
{
public string Name { get; set; }
[ValueMapperIgnore]
public string IgnoredProperty { get; set; }
}
// Or ignore properties at runtime
var ignoredProperties = new HashSet<string> { "Age" };
var destination = ValueMapper.Map<Source, Destination>(source, ignoredProperties);
var sourceList = new List<Source>
{
new Source { Name = "John", Age = 30 },
new Source { Name = "Jane", Age = 25 }
};
var destinationList = ValueMapper.MapList<Source, Destination>(sourceList);
public enum SampleEnum
{
None,
Value1,
Value2
}
public class Source
{
public string EnumValue { get; set; } // Can be "Value1" or "value1"
}
public class Destination
{
public SampleEnum EnumValue { get; set; }
}
public class Source
{
public int IntValue { get; set; }
public double DoubleValue { get; set; }
public string StringNumber { get; set; }
}
public class Destination
{
public long LongValue { get; set; } // Converts from int
public float FloatValue { get; set; } // Converts from double
public int IntFromString { get; set; } // Converts from string
}
public class Source
{
public string Value { get; set; } // Can be null
}
public class Destination
{
public int? NullableValue { get; set; } // Will be null if source is null
}
ValueMapper supports mapping nested objects with multiple levels of depth, including collections and dictionaries:
public class DeepSourceObject
{
public int Id { get; set; }
public string Name { get; set; }
public DeepSourceChild Child { get; set; }
}
public class DeepSourceChild
{
public int ChildId { get; set; }
public string Description { get; set; }
public Dictionary<string, string> Metadata { get; set; }
public List<string> Tags { get; set; }
public DeepSourceGrandChild GrandChild { get; set; }
}
public class DeepSourceGrandChild
{
public int GrandChildId { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedDate { get; set; }
}
// Destination classes with matching structure
public class DeepDestinationObject
{
public int Id { get; set; }
public string Name { get; set; }
public DeepDestinationChild Child { get; set; }
}
// ... similar structure for DeepDestinationChild and DeepDestinationGrandChild
var source = new DeepSourceObject
{
Id = 1,
Name = "Root Object",
Child = new DeepSourceChild
{
ChildId = 100,
Description = "Child Object",
Metadata = new Dictionary<string, string> { { "key1", "value1" } },
Tags = new List<string> { "tag1", "tag2" },
GrandChild = new DeepSourceGrandChild
{
GrandChildId = 1000,
IsActive = true,
CreatedDate = new DateTime(2024, 1, 1)
}
}
};
var destination = ValueMapper.Map<DeepSourceObject, DeepDestinationObject>(source);
// All nested objects are automatically mapped
Collection Mapping Behavior:
- Lists: Creates new List instances (shallow copy - same objects, new container)
- Null sources become empty lists
[]
- Null sources become empty lists
- Dictionaries: Copies references (same instance)
- Null sources remain null
- Complex Objects: Deep mapping with new instances
- Primitive Types: Direct value copying
ValueMapper is designed for high performance. Here are some benchmark results comparing it with other popular mappers:
Mapper | Mean Time (ns) | Allocated (B) | Relative Speed |
---|---|---|---|
ManuallyImplemented | 10.70 ns | 72 B | 1x (baseline) |
Manual | 11.35 ns | 72 B | 1.06x |
Mapster | 49.65 ns | 120 B | 4.6x slower |
AutoMapper | 92.11 ns | 120 B | 8.1x slower |
ValueMapper | 108.08 ns | 72 B | 9.6x slower |
Mapper Collection | Mean Time (ms) | Allocated (MB) | Relative Speed |
---|---|---|---|
ManuallyImplemented | 18.86 ms | 8 MB | 1x (baseline) |
ValueMapper | 20.43 ms | 9.6 MB | 1.08x slower |
AutoMapper | 28.49 ms | 13.3 MB | 1.51x slower |
Mapster | 30.66 ms | 12 MB | 1.63x slower |
Mapper Warmup | Mean Time | Notes |
---|---|---|
ValueMapper | 615.91 ns | Fastest |
Mapster | 720.70 Β΅s | Slower |
AutoMapper | 1.398 ms | Much slower |
-
Single Object Mapping:
- All mappers show minimal overhead for single object mapping
- Mapster shows the best performance among the automated mappers
- ValueMapper performs similarly to other popular mappers
-
Collection Mapping:
- ValueMapper shows strong performance with large collections
- ~43% faster than Mapster
- ~77% faster than AutoMapper
- Close to manually implemented mapping performance
-
Warmup Time:
- ValueMapper has excellent cold start performance
- No significant warmup overhead
- Better startup time compared to both Mapster and AutoMapper
- Bimodal distribution in AutoMapper, Mapster, and ManuallyImplementedMapper suggests occasional performance variability.
- AutoMapper and Mapster have significantly higher memory allocations (up to 1.67Γ).
- ManuallyImplemented options consistently perform best in both speed and memory.
For maximum performance, prefer:
ManuallyImplemented
mapper (best for both individual and collection mapping).- If needing flexibility with a balance of performance:
ValueMapper
. - Avoid
Mapster
andAutoMapper
in large collection transformations if performance is critical.
Run the benchmarks yourself:
cd ValueMapper/Benchmark
dotnet run # Full benchmarks
dotnet run quick # Quick benchmarks
// Clear all caches
ValueMapper.ClearCaches();
// Pre-warm mapping for specific types
ValueMapper.PreWarmMapping<Source, Destination>();
// Clear cache for specific types
ValueMapper.Clear<Source, Destination>();
- No circular reference detection
- No support for mapping private properties
- Collection type conversion (e.g., List to Array) is not supported
- No support for custom value converters
- No support for conditional mapping
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Created and maintained by Jeevanandan J
π LinkedIn
π¦ GitHub
π§ [email protected]