Created
June 18, 2017 11:06
-
-
Save dimzon/7dd96cb37a1ad491322d4d07d4d1f314 to your computer and use it in GitHub Desktop.
Dapper dynamic object generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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