Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
---|---|---|---|---|---|---|
ManualSourceCodeMapping | 1.542 us | 0.0206 us | 0.0183 us | 0.4387 | 0.0076 | 5.38 KB |
AutoMapperMapping | 1.199 us | 0.0221 us | 0.0288 us | 0.3777 | 0.0057 | 4.63 KB |
Last active
April 11, 2024 21:19
-
-
Save mrpmorris/d48f881de623b47e5fc90b48a1875cb6 to your computer and use it in GitHub Desktop.
Proof that automapper can be faster than your own manually written code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net8.0</TargetFramework> | |
<ImplicitUsings>enable</ImplicitUsings> | |
<Nullable>enable</Nullable> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="AutoMapper" Version="13.0.1" /> | |
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" /> | |
</ItemGroup> | |
</Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ConsoleApp154; | |
public class Parent | |
{ | |
public DateTime CreatedUtc { get; set; } = DateTime.UtcNow; | |
public string Name { get; set; } = "Bob"; | |
public List<Child> Children { get; set; } = []; | |
} | |
public class Child | |
{ | |
public DateTime CreatedUtc { get; set; } = DateTime.UtcNow; | |
public string Name { get; set; } = "Bob"; | |
} | |
public class ParentDto | |
{ | |
public DateTime CreatedUtc { get; set; } = DateTime.MinValue; | |
public string Name { get; set; } = ""; | |
public ChildDto[] Children { get; set; } = []; | |
} | |
public class ChildDto | |
{ | |
public DateTime CreatedUtc { get; set; } = DateTime.MinValue; | |
public string Name { get; set; } = ""; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using AutoMapper; | |
namespace ConsoleApp154; | |
public static class ManualMapperImpl | |
{ | |
public static ParentDto[] Map(IEnumerable<Parent> parents) => | |
parents | |
.Select(x => | |
new ParentDto | |
{ | |
CreatedUtc = x.CreatedUtc, | |
Name = x.Name, | |
Children = x.Children | |
.Select(x => | |
new ChildDto | |
{ | |
CreatedUtc = x.CreatedUtc, | |
Name = x.Name | |
} | |
) | |
.ToArray() | |
} | |
) | |
.ToArray(); | |
} | |
public static class AutoMapperImpl | |
{ | |
private static readonly IMapper Mapper = new MapperConfiguration(x => | |
{ | |
x.CreateMap<Parent, ParentDto>(); | |
x.CreateMap<Child, ChildDto>(); | |
}) | |
.CreateMapper(); | |
public static ParentDto[] Map(IEnumerable<Parent> parents) => Mapper.Map<ParentDto[]>(parents); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
namespace ConsoleApp154; | |
public class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
BenchmarkRunner.Run<SimpleBenchmark>(); | |
} | |
} | |
public class SimpleBenchmark | |
{ | |
private static readonly Parent[] SourceData = CreateData(); | |
[Benchmark] | |
public void ManualSourceCodeMapping() | |
{ | |
ParentDto[] result = ManualMapperImpl.Map(SourceData); | |
ValidateParents(result); | |
} | |
[Benchmark] | |
public void AutoMapperMapping() | |
{ | |
ParentDto[] result = AutoMapperImpl.Map(SourceData); | |
ValidateParents(result); | |
} | |
private static Parent[] CreateData() => | |
Enumerable.Range(1, 10).Select(x => | |
new Parent | |
{ | |
Children = Enumerable.Range(1, 10).Select(_ => new Child()).ToList() | |
}) | |
.ToArray(); | |
private static void ValidateParents(ParentDto[] parents) | |
{ | |
if (parents.Length != SourceData.Length) throw new Exception("Lengths are different"); | |
for (int parentIndex = 0; parentIndex < SourceData.Length; parentIndex++) | |
{ | |
Parent parent = SourceData[parentIndex]; | |
ParentDto parentDto = parents[parentIndex]; | |
ValidateParentData(parentIndex, parent, parentDto); | |
} | |
} | |
private static void ValidateParentData(int parentIndex, Parent parent, ParentDto parentDto) | |
{ | |
if (parentDto.CreatedUtc != parent.CreatedUtc) throw new Exception($"[{parentIndex}].CreatedUtc"); | |
if (parentDto.Name != parent.Name) throw new Exception($"[{parentIndex}].Name"); | |
if (parentDto.Children.Length != parent.Children.Count) throw new Exception($"[{parentIndex}].Children.Count"); | |
for (int childIndex = 0; childIndex < parent.Children.Count; childIndex++) | |
{ | |
Child child = parent.Children[childIndex]; | |
ChildDto childDto = parentDto.Children[childIndex]; | |
ValidateChildData(parentIndex, childIndex, child, childDto); | |
} | |
} | |
private static void ValidateChildData(int parentIndex, int childIndex, Child child, ChildDto childDto) | |
{ | |
if (childDto.CreatedUtc != child.CreatedUtc) throw new Exception($"[{parentIndex}, {childIndex}].CreatedUtc"); | |
if (childDto.Name != child.Name) throw new Exception($"[{parentIndex}, {childIndex}].Name"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
cough