It does the same thing as the linq version but requires separate assign blocks for each combination of field and property.
using System; using System.Collections.Generic; using System.Linq; using System.Reflection.Emit; namespace typeoverridedemostrater { static class SuperConverter<T1, T2> where T2 : new() { private static Dictionary<Tuple<System.Type, System.Type>, MethodInvoker> converters = new Dictionary<Tuple<System.Type, System.Type>, MethodInvoker>(); delegate T2 MethodInvoker(T1 inpt); static public T2 Convert(T1 i) { var key = new Tuple<System.Type, System.Type>(typeof(T2), typeof(T1)); if (!converters.ContainsKey(key)) { DynamicMethod dm = new DynamicMethod("xmethod", typeof(T2), new Type[] { typeof(T1) }, typeof(T2)); ILGenerator il = dm.GetILGenerator(); il.DeclareLocal(typeof(T2)); il.Emit(OpCodes.Newobj, typeof(T2).GetConstructor(System.Type.EmptyTypes)); il.Emit(OpCodes.Stloc_0); (from z in typeof(T1).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) join y in typeof(T2).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, typeof(T1).GetField(a)); il.Emit(OpCodes.Stfld, typeof(T2).GetField(a)); }); (from z in typeof(T1).GetProperties().Select(a => new { name = a.Name, type = a.PropertyType }) join y in typeof(T2).GetProperties().Where(b => b.CanWrite).Select(a => new { name = a.Name, type = a.PropertyType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, typeof(T1).GetProperty(a).GetGetMethod()); il.Emit(OpCodes.Callvirt, typeof(T2).GetProperty(a).GetSetMethod()); }); (from z in typeof(T1).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) join y in typeof(T2).GetProperties().Where(b => b.CanWrite).Select(a => new { name = a.Name, type = a.PropertyType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, typeof(T1).GetField(a)); il.Emit(OpCodes.Callvirt, typeof(T2).GetProperty(a).GetSetMethod()); }); (from z in typeof(T1).GetProperties().Select(a => new { name = a.Name, type = a.PropertyType }) join y in typeof(T2).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, typeof(T1).GetProperty(a).GetGetMethod()); il.Emit(OpCodes.Stfld, typeof(T2).GetField(a)); }); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); var dg = (MethodInvoker)dm.CreateDelegate(typeof(MethodInvoker)); converters.Add(key, dg); } return (T2)converters[key](i); } } }
Compared to the Linq version at 100 million repetitions (at lower numbers the results are less predictable):
Linq: 94.579 seconds vs MSIL: 93.423 seconds
Some of that time is consumed dealing with the delegates, so you can transform that into a full dynamic assembly where you can have base classes and real instance references like this:
using System; using System.Collections.Generic; using System.Linq; using System.Reflection.Emit; using System.Threading; using System.Reflection; namespace typeoverridedemostrater { static class SuperConverterII<T1, T2> where T2 : new() { private static Dictionary<Tuple<System.Type, System.Type>, convertbase<T1, T2>> converters = new Dictionary<Tuple<System.Type, System.Type>, convertbase<T1, T2>>(); static public T2 Convert(T1 i) { var key = new Tuple<System.Type, System.Type>(typeof(T2), typeof(T1)); if (!converters.ContainsKey(key)) { var xassemblybuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("xassembly"), System.Reflection.Emit.AssemblyBuilderAccess.Run); var xtype = xassemblybuilder.DefineDynamicModule("xmodule").DefineType("xtype", TypeAttributes.Public, typeof(convertbase<T1, T2>)); var xfunction = xtype.DefineMethod("convert", MethodAttributes.Public | MethodAttributes.Virtual, typeof(T2), new System.Type[] { typeof(T1) }); xtype.DefineMethodOverride(xfunction, typeof(convertbase<T1, T2>).GetMethod("convert")); var il = xfunction.GetILGenerator(); il.DeclareLocal(typeof(T2)); il.Emit(OpCodes.Newobj, typeof(T2).GetConstructor(System.Type.EmptyTypes)); il.Emit(OpCodes.Stloc_0); (from z in typeof(T1).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) join y in typeof(T2).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldfld, typeof(T1).GetField(a)); il.Emit(OpCodes.Stfld, typeof(T2).GetField(a)); }); (from z in typeof(T1).GetProperties().Select(a => new { name = a.Name, type = a.PropertyType }) join y in typeof(T2).GetProperties().Where(b => b.CanWrite).Select(a => new { name = a.Name, type = a.PropertyType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Callvirt, typeof(T1).GetProperty(a).GetGetMethod()); il.Emit(OpCodes.Callvirt, typeof(T2).GetProperty(a).GetSetMethod()); }); (from z in typeof(T1).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) join y in typeof(T2).GetProperties().Where(b => b.CanWrite).Select(a => new { name = a.Name, type = a.PropertyType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldfld, typeof(T1).GetField(a)); il.Emit(OpCodes.Callvirt, typeof(T2).GetProperty(a).GetSetMethod()); }); (from z in typeof(T1).GetProperties().Select(a => new { name = a.Name, type = a.PropertyType }) join y in typeof(T2).GetFields().Select(a => new { name = a.Name, type = a.FieldType }) on z equals y select z.name).ToList().ForEach(a => { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Callvirt, typeof(T1).GetProperty(a).GetGetMethod()); il.Emit(OpCodes.Stfld, typeof(T2).GetField(a)); }); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); xtype.CreateType(); converters.Add(key, (convertbase<T1, T2>)xassemblybuilder.CreateInstance("xtype")); } return converters[key].convert(i); } } public abstract class convertbase<T1, T2> { public abstract T2 convert(T1 i); } }
Compared to the original MSIL version at 100 million repetitions:
Delegate MSIL: 93.423 seconds vs Base Class MSIL: 91.814 seconds
At REALLY high volumes that is significant, and I am certain that someone better at MSIL than I could probably make it a bit faster still, but for my purposes the Linq version is more than sufficient as I find the MSIL versions a little hard to work in for the level of benefit in return.