Created
May 3, 2020 11:28
-
-
Save 0x1000000/5ee4d6d2fdf426f64b60a2cbd3263a4a to your computer and use it in GitHub Desktop.
For Habr https://habr.com/ru/post/499562
This file contains 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 System; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
namespace LinqReflPlay | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
BenchmarkRunner.Run<BenchMark>(); | |
} | |
} | |
[MemoryDiagnoser] | |
public class BenchMark | |
{ | |
public Action<ContactA, ContactB> LinqCopier; | |
public Action<ContactA, ContactB> ReflectionCopier; | |
public ContactA Source; | |
public ContactB Target; | |
[GlobalSetup] | |
public void Setup() | |
{ | |
if (this.LinqCopier != null) | |
{ | |
throw new Exception("AA"); | |
} | |
this.LinqCopier = Algs.BuildLinqCopier(); | |
this.ReflectionCopier = Algs.BuildReflectionCopier(); | |
this.Source = new ContactA | |
{ | |
FirstName = "John", | |
LastName = "Smith", | |
EMail = "Email" | |
}; | |
this.Target = new ContactB(); | |
} | |
[Params(1, 100)] | |
public int N = 1; | |
[Benchmark] | |
public void Linq() | |
{ | |
for (int i = 0; i < N; i++) | |
{ | |
this.LinqCopier(this.Source, this.Target); | |
} | |
} | |
[Benchmark] | |
public void Reflection() | |
{ | |
for (int i = 0; i < N; i++) | |
{ | |
this.ReflectionCopier(this.Source, this.Target); | |
} | |
} | |
} | |
public class Algs | |
{ | |
public static Action<ContactA, ContactB> BuildLinqCopier() | |
{ | |
var propsA = typeof(ContactA).GetProperties(); | |
var propsB = typeof(ContactB).GetProperties(); | |
var setters = propsA.Select(a => (pA: a, pB: propsB.First(b => b.Name == a.Name))).Select(t => PropCopier(t.pA, t.pB)).ToArray(); | |
return (a, b) => | |
{ | |
for (int i = 0; i < setters.Length; i++) | |
{ | |
setters[i](a, b); | |
} | |
}; | |
Action<ContactA, ContactB> PropCopier(PropertyInfo propertyInfoA, PropertyInfo propertyInfoB) | |
{ | |
var pa = Expression.Parameter(typeof(ContactA)); | |
var pb = Expression.Parameter(typeof(ContactB)); | |
var body = Expression.Call(pb, propertyInfoB.SetMethod, Expression.Call(pa, propertyInfoA.GetMethod)); | |
return (Action<ContactA, ContactB>)Expression.Lambda(body, false, pa, pb).Compile(); | |
} | |
} | |
public static Action<ContactA, ContactB> BuildReflectionCopier() | |
{ | |
var propsA = typeof(ContactA).GetProperties(); | |
var propsB = typeof(ContactB).GetProperties(); | |
var setters = propsA | |
.Select(a => (pA: a, pB: propsB.First(b => b.Name == a.Name))) | |
.Select(t => (pAGet: t.pA.GetMethod, pBSet: t.pB.SetMethod)) | |
.ToArray(); | |
var setterParamsBuffer = new object[1]; | |
return (a, b) => | |
{ | |
for (int i = 0; i < setters.Length; i++) | |
{ | |
var getSet = setters[i]; | |
setterParamsBuffer[0] = getSet.pAGet.Invoke(a, null); | |
getSet.pBSet.Invoke(b, setterParamsBuffer); | |
} | |
}; | |
} | |
} | |
public class ContactA | |
{ | |
public string FirstName { get; set; } | |
public string LastName { get; set; } | |
public string EMail { get; set; } | |
} | |
public class ContactB | |
{ | |
public string FirstName { get; set; } | |
public string LastName { get; set; } | |
public string EMail { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment