Skip to content

Instantly share code, notes, and snippets.

@0x1000000
Created May 3, 2020 11:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0x1000000/5ee4d6d2fdf426f64b60a2cbd3263a4a to your computer and use it in GitHub Desktop.
Save 0x1000000/5ee4d6d2fdf426f64b60a2cbd3263a4a to your computer and use it in GitHub Desktop.
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