Skip to content

Instantly share code, notes, and snippets.

@dimzon
Created June 18, 2017 11:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dimzon/7dd96cb37a1ad491322d4d07d4d1f314 to your computer and use it in GitHub Desktop.
Save dimzon/7dd96cb37a1ad491322d4d07d4d1f314 to your computer and use it in GitHub Desktop.
Dapper dynamic object generation
using (var cn=Db.NewSqlConnection())
{
var sql = @"select
0, -- no name column will be skiped,
1 i1, 2 i1, -- 2 columns same type: single int? i1{get;set;} property
newid() o1, 3 o1, -- 2 columns different type: single object o1{get;set} property
'foo' bar,
'wow!' [even so property! amazing :)]
";
using (var a = cn.ExecuteReader(sql))
{
var type = RowClassTypeBuilder.CompileResultType(a);
var list = a.Parse(type).AsList();
dynamic x = list[0]; // inspect in watch ;)
dataGridView1.DataSource = list;
}
}
namespace ePrinting
{
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using PropertyAttributes = System.Reflection.PropertyAttributes;
// based on https://stackoverflow.com/questions/3862226/how-to-dynamically-create-a-class-in-c
public static class RowClassTypeBuilder
{
//TODO: Cache type per DataReader (key is fieldlist+types)
//TODO: maybe better to generate Generic types (like .NET anonymous types)
public static Type CompileResultType(IDataReader dataReader)
{
var tb = GetTypeBuilder();
tb.DefineDefaultConstructor(MethodAttributes.Public
| MethodAttributes.SpecialName
| MethodAttributes.RTSpecialName);
var nullable = typeof(Nullable<>);
var props = Enumerable.Range(0, dataReader.FieldCount)
.Select(it => new {n = dataReader.GetName(it), t = dataReader.GetFieldType(it)})
.Where(it => !string.IsNullOrEmpty(it.n))
.Select(it => new
{
it.n,
t = it.t.IsValueType && Nullable.GetUnderlyingType(it.t) == null
? nullable.MakeGenericType(it.t)
: it.t
})
.GroupBy(it => it.n)
.Select(it => new
{
n = it.Key,
ta = it.Select(e => e.t).Distinct().ToArray()
})
.Select(it => new {it.n, t = it.ta.Length != 1 ? typeof(object) : it.ta[0]});
foreach (var prop in props)
CreateProperty(tb, prop.n, prop.t);
return tb.CreateType();
}
private static TypeBuilder GetTypeBuilder()
{
var typeSignature = Guid.NewGuid().ToString("P");
var an = new AssemblyName(typeSignature);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
var tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
var fieldName = Guid.NewGuid().ToString("P"); //"_<>$" + propertyName;
var fieldBuilder = tb.DefineField(fieldName, propertyType, FieldAttributes.Private);
var propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
var getPropMthdBldr = tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType,
Type.EmptyTypes);
var getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
var setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] {propertyType});
var setIl = setPropMthdBldr.GetILGenerator();
var modifyProperty = setIl.DefineLabel();
var exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment