A lightweight, high-performance object-to-object mapper for .NET
$ dotnet add package ValueMapperA 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).
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:
[]ValueMapper is designed for high performance. Here are some benchmark results comparing it with other popular mappers:
| Mapper | Performance | Relative Slowdown |
|---|---|---|
| Manual (baseline) | 0.000ms | 1x |
| ValueMapper | 0.001ms | 11.95x slower |
| AutoMapper | 0.002ms | 12.67x slower |
| Mapster | 0.001ms | 8.11x slower |
| ManuallyImplemented | 0.001ms | 7.29x slower |
| Mapper | Time per Operation |
|---|---|
| ValueMapperCollection | 39.840ms |
| AutoMapperCollection | 70.800ms |
| MapsterCollection | 65.340ms |
| ManuallyImplementedCollection | 45.310ms |
| Mapper | Warmup Time |
|---|---|
| ValueMapper | 0ms |
| AutoMapper | 7ms |
| Mapster | 10ms |
| ManuallyImplemented | No warmup needed |
Single Object Mapping:
Collection Mapping:
Warmup Time:
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>();
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.