代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
namespace FastMapper
{
public delegate TTarget MapMethod<TTarget, TSource>(TSource source);
public static class FastMapper<TTarget,TSource>
{
private static MapMethod<TTarget, TSource> mapMethod;
public static MapMethod<TTarget, TSource> GetMapMethod()
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod;
}
public static TTarget Map(TSource source)
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod(source);
}
private static MapMethod<TTarget, TSource> CreateMapMethod(Type targetType, Type sourceType)
{
DynamicMethod map = new DynamicMethod("Map", targetType, new Type[] { sourceType }, typeof(TTarget).Module);
ILGenerator il = map.GetILGenerator();
ConstructorInfo ci = targetType.GetConstructor(new Type[0]);
il.DeclareLocal(targetType);
il.Emit(OpCodes.Newobj, ci);
il.Emit(OpCodes.Stloc_0);
foreach (var sourcePropertyInfo in sourceType.GetProperties())
{
var targetPropertyInfo = (from p in targetType.GetProperties()
where p.Name == sourcePropertyInfo.Name && p.PropertyType == sourcePropertyInfo.PropertyType
select p).FirstOrDefault();
if (targetPropertyInfo == null) continue;
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, sourcePropertyInfo.GetGetMethod());
il.Emit(OpCodes.Callvirt, targetPropertyInfo.GetSetMethod());
}
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
return (MapMethod<TTarget, TSource>)map.CreateDelegate(typeof(MapMethod<TTarget, TSource>));
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
namespace FastMapper
{
public delegate TTarget MapMethod<TTarget, TSource>(TSource source);
public static class FastMapper<TTarget,TSource>
{
private static MapMethod<TTarget, TSource> mapMethod;
public static MapMethod<TTarget, TSource> GetMapMethod()
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod;
}
public static TTarget Map(TSource source)
{
if (mapMethod == null)
{
mapMethod = CreateMapMethod(typeof(TTarget), typeof(TSource));
}
return mapMethod(source);
}
private static MapMethod<TTarget, TSource> CreateMapMethod(Type targetType, Type sourceType)
{
DynamicMethod map = new DynamicMethod("Map", targetType, new Type[] { sourceType }, typeof(TTarget).Module);
ILGenerator il = map.GetILGenerator();
ConstructorInfo ci = targetType.GetConstructor(new Type[0]);
il.DeclareLocal(targetType);
il.Emit(OpCodes.Newobj, ci);
il.Emit(OpCodes.Stloc_0);
foreach (var sourcePropertyInfo in sourceType.GetProperties())
{
var targetPropertyInfo = (from p in targetType.GetProperties()
where p.Name == sourcePropertyInfo.Name && p.PropertyType == sourcePropertyInfo.PropertyType
select p).FirstOrDefault();
if (targetPropertyInfo == null) continue;
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, sourcePropertyInfo.GetGetMethod());
il.Emit(OpCodes.Callvirt, targetPropertyInfo.GetSetMethod());
}
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
return (MapMethod<TTarget, TSource>)map.CreateDelegate(typeof(MapMethod<TTarget, TSource>));
}
}
}
下面是测试
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using System.Diagnostics;
using System.Linq.Expressions;
namespace FastMapper
{
public class TargetModel
{
public string Name { get; set; }
public int Age { get; set; }
public object Pic { get; set; }
}
public class SourceModel
{
public string Name { get; set; }
public int Age { get; set; }
public object Pic { get; set; }
}
class Program
{
static void Main(string[] args)
{
mytest();
Console.ReadKey();
}
private static void mytest()
{
int count = 1000000;
SourceModel source = new SourceModel { Name = "xhan", Age = 33, Pic = new object() };
long normal = Test1(count, source);
Console.WriteLine("Normal Map Time:{0}", normal);
long faster = Test2(count, source);
Console.WriteLine("FastMapper Time:{0}", faster);
Test3(count, source);
Console.WriteLine((double)faster / normal);
}
private static long Test3(int count, SourceModel source)
{
Stopwatch stopwatch1 = new Stopwatch();
stopwatch1.Start();
for (int i = 0; i < count; i++)
{
TargetModel target = ExpMapper<TargetModel,SourceModel>.Map(source);
System.Diagnostics.Debug.Assert(target.Name == source.Name);
System.Diagnostics.Debug.Assert(target.Age == source.Age);
System.Diagnostics.Debug.Assert(target.Pic == source.Pic);
}
stopwatch1.Stop();
long faster = stopwatch1.ElapsedMilliseconds;
Console.WriteLine("ExpMapper Time:{0}", faster);
return faster;
}
private static long Test1(int count, SourceModel source)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < count; i++)
{
TargetModel target = NormalMap(source);
System.Diagnostics.Debug.Assert(target.Name == source.Name);
System.Diagnostics.Debug.Assert(target.Age == source.Age);
System.Diagnostics.Debug.Assert(target.Pic == source.Pic);
}
stopwatch.Stop();
long normal = stopwatch.ElapsedMilliseconds;
return normal;
}
private static long Test2(int count, SourceModel source)
{
Stopwatch stopwatch1 = new Stopwatch();
stopwatch1.Start();
for (int i = 0; i < count; i++)
{
TargetModel target = FastMapper<TargetModel,SourceModel>.Map(source);
//TargetModel target = mapper.Invoke(source);
System.Diagnostics.Debug.Assert(target.Name == source.Name);
System.Diagnostics.Debug.Assert(target.Age == source.Age);
System.Diagnostics.Debug.Assert(target.Pic == source.Pic);
}
stopwatch1.Stop();
long faster = stopwatch1.ElapsedMilliseconds;
return faster;
}
public static TargetModel NormalMap(SourceModel source)
{
TargetModel target = new TargetModel();
target.Age = source.Age;
target.Name = source.Name;
target.Pic = source.Pic;
return target;
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using System.Diagnostics;
using System.Linq.Expressions;
namespace FastMapper
{
public class TargetModel
{
public string Name { get; set; }
public int Age { get; set; }
public object Pic { get; set; }
}
public class SourceModel
{
public string Name { get; set; }
public int Age { get; set; }
public object Pic { get; set; }
}
class Program
{
static void Main(string[] args)
{
mytest();
Console.ReadKey();
}
private static void mytest()
{
int count = 1000000;
SourceModel source = new SourceModel { Name = "xhan", Age = 33, Pic = new object() };
long normal = Test1(count, source);
Console.WriteLine("Normal Map Time:{0}", normal);
long faster = Test2(count, source);
Console.WriteLine("FastMapper Time:{0}", faster);
Test3(count, source);
Console.WriteLine((double)faster / normal);
}
private static long Test3(int count, SourceModel source)
{
Stopwatch stopwatch1 = new Stopwatch();
stopwatch1.Start();
for (int i = 0; i < count; i++)
{
TargetModel target = ExpMapper<TargetModel,SourceModel>.Map(source);
System.Diagnostics.Debug.Assert(target.Name == source.Name);
System.Diagnostics.Debug.Assert(target.Age == source.Age);
System.Diagnostics.Debug.Assert(target.Pic == source.Pic);
}
stopwatch1.Stop();
long faster = stopwatch1.ElapsedMilliseconds;
Console.WriteLine("ExpMapper Time:{0}", faster);
return faster;
}
private static long Test1(int count, SourceModel source)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < count; i++)
{
TargetModel target = NormalMap(source);
System.Diagnostics.Debug.Assert(target.Name == source.Name);
System.Diagnostics.Debug.Assert(target.Age == source.Age);
System.Diagnostics.Debug.Assert(target.Pic == source.Pic);
}
stopwatch.Stop();
long normal = stopwatch.ElapsedMilliseconds;
return normal;
}
private static long Test2(int count, SourceModel source)
{
Stopwatch stopwatch1 = new Stopwatch();
stopwatch1.Start();
for (int i = 0; i < count; i++)
{
TargetModel target = FastMapper<TargetModel,SourceModel>.Map(source);
//TargetModel target = mapper.Invoke(source);
System.Diagnostics.Debug.Assert(target.Name == source.Name);
System.Diagnostics.Debug.Assert(target.Age == source.Age);
System.Diagnostics.Debug.Assert(target.Pic == source.Pic);
}
stopwatch1.Stop();
long faster = stopwatch1.ElapsedMilliseconds;
return faster;
}
public static TargetModel NormalMap(SourceModel source)
{
TargetModel target = new TargetModel();
target.Age = source.Age;
target.Name = source.Name;
target.Pic = source.Pic;
return target;
}
}
}
性能理论上和手写的复制一样!