public static class Extensions { public static DataTable ToDataTable(this IEnumerable source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } var table = Cache.SchemeFactory(); foreach (var item in source) { var row = table.NewRow(); Cache.Fill(row, item); table.Rows.Add(row); } return table; } private static class Cache { // ReSharper disable StaticMemberInGenericType private static readonly PropertyInfo[] PropertyInfos; // ReSharper restore StaticMemberInGenericType // ReSharper disable StaticMemberInGenericType public static readonly Func SchemeFactory; // ReSharper restore StaticMemberInGenericType public static readonly Action Fill; static Cache() { PropertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); SchemeFactory = GenerateSchemeFactory(); Fill = GenerateFill(); } private static Func GenerateSchemeFactory() { var dynamicMethod = new DynamicMethod($"__Extensions__SchemeFactory__Of__{typeof(T).Name}", typeof(DataTable), Type.EmptyTypes, typeof(T), true); var generator = dynamicMethod.GetILGenerator(); // ReSharper disable AssignNullToNotNullAttribute generator.Emit(OpCodes.Newobj, typeof(DataTable).GetConstructor(Type.EmptyTypes)); // ReSharper restore AssignNullToNotNullAttribute generator.Emit(OpCodes.Dup); // ReSharper disable PossibleNullReferenceException generator.Emit(OpCodes.Callvirt, typeof(DataTable).GetProperty("Columns").GetMethod); // ReSharper restore PossibleNullReferenceException foreach (var propertyInfo in PropertyInfos) { generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Ldstr, propertyInfo.Name); generator.Emit(OpCodes.Ldtoken, propertyInfo.PropertyType); // ReSharper disable AssignNullToNotNullAttribute generator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new[] {typeof(RuntimeTypeHandle)})); // ReSharper restore AssignNullToNotNullAttribute // ReSharper disable AssignNullToNotNullAttribute generator.Emit(OpCodes.Callvirt, typeof(DataColumnCollection).GetMethod("Add", new[] {typeof(string), typeof(Type)})); // ReSharper restore AssignNullToNotNullAttribute generator.Emit(OpCodes.Pop); } generator.Emit(OpCodes.Pop); generator.Emit(OpCodes.Ret); return (Func) dynamicMethod.CreateDelegate(typeof(Func)); } private static Action GenerateFill() { var dynamicMethod = new DynamicMethod($"__Extensions__Fill__Of__{typeof(T).Name}", typeof(void), new[] { typeof(DataRow), typeof(T) }, typeof(T), true); var generator = dynamicMethod.GetILGenerator(); for (var i = 0; i < PropertyInfos.Length; i++) { generator.Emit(OpCodes.Ldarg_0); switch (i) { case 0: generator.Emit(OpCodes.Ldc_I4_0); break; case 1: generator.Emit(OpCodes.Ldc_I4_1); break; case 2: generator.Emit(OpCodes.Ldc_I4_2); break; case 3: generator.Emit(OpCodes.Ldc_I4_3); break; case 4: generator.Emit(OpCodes.Ldc_I4_4); break; case 5: generator.Emit(OpCodes.Ldc_I4_5); break; case 6: generator.Emit(OpCodes.Ldc_I4_6); break; case 7: generator.Emit(OpCodes.Ldc_I4_7); break; case 8: generator.Emit(OpCodes.Ldc_I4_8); break; default: if (i <= 127) { generator.Emit(OpCodes.Ldc_I4_S, (byte)i); } else { generator.Emit(OpCodes.Ldc_I4, i); } break; } generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Callvirt, PropertyInfos[i].GetGetMethod(true)); if (PropertyInfos[i].PropertyType.IsValueType) { generator.Emit(OpCodes.Box, PropertyInfos[i].PropertyType); } // ReSharper disable AssignNullToNotNullAttribute generator.Emit(OpCodes.Callvirt, typeof(DataRow).GetMethod("set_Item", new[] { typeof(int), typeof(object) })); // ReSharper restore AssignNullToNotNullAttribute } generator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } } }