Skip to content

Instantly share code, notes, and snippets.

@echofool
Created October 18, 2019 02:40
Show Gist options
  • Save echofool/27a42b59d523055c67c05f1dce5c7e0f to your computer and use it in GitHub Desktop.
Save echofool/27a42b59d523055c67c05f1dce5c7e0f to your computer and use it in GitHub Desktop.
POCO to DataTable
public static class Extensions
{
public static DataTable ToDataTable<T>(this IEnumerable<T> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var table = Cache<T>.SchemeFactory();
foreach (var item in source)
{
var row = table.NewRow();
Cache<T>.Fill(row, item);
table.Rows.Add(row);
}
return table;
}
private static class Cache<T>
{
// ReSharper disable StaticMemberInGenericType
private static readonly PropertyInfo[] PropertyInfos;
// ReSharper restore StaticMemberInGenericType
// ReSharper disable StaticMemberInGenericType
public static readonly Func<DataTable> SchemeFactory;
// ReSharper restore StaticMemberInGenericType
public static readonly Action<DataRow, T> Fill;
static Cache()
{
PropertyInfos =
typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
SchemeFactory = GenerateSchemeFactory();
Fill = GenerateFill();
}
private static Func<DataTable> 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<DataTable>) dynamicMethod.CreateDelegate(typeof(Func<DataTable>));
}
private static Action<DataRow, T> 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<DataRow, T>)dynamicMethod.CreateDelegate(typeof(Action<DataRow, T>));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment