代码
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;
}
}
}
性能理论上和手写的复制一样!