ServiceProducer.cs
· 5.3 KiB · C#
Bruto
using NHibernate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace DatabaseSample {
public static class ServiceProducer<T> {
public static T ProduceService() {
var myType = CompileResultType<T>();
return (T)Activator.CreateInstance(myType);
}
public static Type CompileResultType<T>() {
TypeBuilder tb = GetTypeBuilder<T>();
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
return tb.CreateType();
}
private static TypeBuilder GetTypeBuilder<T>() {
var typeSignature = "customType_" + typeof(T).Name;
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, typeof(T));
typeof(T).GetMethods().ToList().ForEach(m => {
MethodBuilder mbM = tb.DefineMethod(m.Name, MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig,
m.ReturnType,
m.GetParameters().ToList().Select(a => a.ParameterType).ToArray());
var il = mbM.GetILGenerator();
il.DeclareLocal(typeof(ISessionFactory));
il.DeclareLocal(typeof(ISession));
il.DeclareLocal(typeof(ITransaction));
il.DeclareLocal(typeof(Exception));
if (!typeof(void).IsAssignableFrom(m.ReturnType)) {
il.DeclareLocal(m.ReturnType);
}
Label transactionNull = il.DefineLabel();
Label exit = il.DefineLabel();
// try {
il.BeginExceptionBlock();
// BaseService._session = BaseService._sessionFactory.OpenSession();
writeLine(il, "GettingSession");
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_sessionFactory"));
il.Emit(OpCodes.Stloc_0);
writeLine(il, "Session got!");
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Call, typeof(ISessionFactory).GetMethod("OpenSession", new Type[0]));
il.Emit(OpCodes.Stloc_1);
writeLine(il, "Saving session");
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Stsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static));
il.Emit(OpCodes.Nop);
// transaction = BaseService._session.BeginTransaction()
writeLine(il, "Creating Transaction");
il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static));
il.Emit(OpCodes.Call, typeof(ISession).GetMethod("BeginTransaction", new Type[0]));
il.Emit(OpCodes.Stloc_2);
// base.{thismethod}({parameters})
writeLine(il, "Calling parent");
il.Emit(OpCodes.Ldarg_0);
UInt16 i = 1;
m.GetParameters().ToList().ForEach(a => {
il.Emit(OpCodes.Ldarg, i);
i++;
});
il.EmitCall(OpCodes.Call, m, new Type[0]);
if (!typeof(void).IsAssignableFrom(m.ReturnType)) {
il.Emit(OpCodes.Stloc, 4);
}
// transaction.Commit();
writeLine(il, "Commiting Transaction");
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Call, typeof(ITransaction).GetMethod("Commit"));
// } catch (Exception) {
il.BeginCatchBlock(typeof(Exception));
il.Emit(OpCodes.Pop);
// transaction.Commit();
writeLine(il, "Rolling back Transaction");
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Brfalse_S, transactionNull);
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Call, typeof(ITransaction).GetMethod("Rollback"));
writeLine(il, "Exception got!");
il.MarkLabel(transactionNull);
il.Emit(OpCodes.Rethrow);
// } finally {
il.BeginFinallyBlock();
// BaseService._session.Close();
writeLine(il, "Closing session");
il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static));
il.Emit(OpCodes.Brfalse_S, exit);
il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static));
il.Emit(OpCodes.Call, typeof(ISession).GetMethod("Close"));
il.Emit(OpCodes.Pop);
//}
il.EndExceptionBlock();
// return {returndata}
if (!typeof(void).IsAssignableFrom(m.ReturnType)) {
il.Emit(OpCodes.Ldloc, 4);
}
il.MarkLabel(exit);
il.Emit(OpCodes.Ret);
});
return tb;
}
private static void writeLine(ILGenerator il, string line) {
il.Emit(OpCodes.Ldstr, line);
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
}
}
}
| 1 | using NHibernate; |
| 2 | using System; |
| 3 | using System.Collections.Generic; |
| 4 | using System.Linq; |
| 5 | using System.Reflection; |
| 6 | using System.Reflection.Emit; |
| 7 | using System.Text; |
| 8 | using System.Threading.Tasks; |
| 9 | |
| 10 | namespace DatabaseSample { |
| 11 | public static class ServiceProducer<T> { |
| 12 | |
| 13 | public static T ProduceService() { |
| 14 | var myType = CompileResultType<T>(); |
| 15 | return (T)Activator.CreateInstance(myType); |
| 16 | } |
| 17 | |
| 18 | public static Type CompileResultType<T>() { |
| 19 | TypeBuilder tb = GetTypeBuilder<T>(); |
| 20 | ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); |
| 21 | |
| 22 | return tb.CreateType(); |
| 23 | } |
| 24 | private static TypeBuilder GetTypeBuilder<T>() { |
| 25 | var typeSignature = "customType_" + typeof(T).Name; |
| 26 | var an = new AssemblyName(typeSignature); |
| 27 | AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); |
| 28 | ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); |
| 29 | TypeBuilder tb = moduleBuilder.DefineType(typeSignature |
| 30 | , TypeAttributes.Public | |
| 31 | TypeAttributes.Class | |
| 32 | TypeAttributes.AutoClass | |
| 33 | TypeAttributes.AnsiClass | |
| 34 | TypeAttributes.BeforeFieldInit | |
| 35 | TypeAttributes.AutoLayout |
| 36 | , typeof(T)); |
| 37 | |
| 38 | typeof(T).GetMethods().ToList().ForEach(m => { |
| 39 | MethodBuilder mbM = tb.DefineMethod(m.Name, MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, |
| 40 | m.ReturnType, |
| 41 | m.GetParameters().ToList().Select(a => a.ParameterType).ToArray()); |
| 42 | |
| 43 | var il = mbM.GetILGenerator(); |
| 44 | |
| 45 | il.DeclareLocal(typeof(ISessionFactory)); |
| 46 | il.DeclareLocal(typeof(ISession)); |
| 47 | il.DeclareLocal(typeof(ITransaction)); |
| 48 | il.DeclareLocal(typeof(Exception)); |
| 49 | if (!typeof(void).IsAssignableFrom(m.ReturnType)) { |
| 50 | il.DeclareLocal(m.ReturnType); |
| 51 | } |
| 52 | |
| 53 | Label transactionNull = il.DefineLabel(); |
| 54 | Label exit = il.DefineLabel(); |
| 55 | |
| 56 | // try { |
| 57 | il.BeginExceptionBlock(); |
| 58 | |
| 59 | // BaseService._session = BaseService._sessionFactory.OpenSession(); |
| 60 | writeLine(il, "GettingSession"); |
| 61 | il.Emit(OpCodes.Nop); |
| 62 | il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_sessionFactory")); |
| 63 | il.Emit(OpCodes.Stloc_0); |
| 64 | |
| 65 | writeLine(il, "Session got!"); |
| 66 | il.Emit(OpCodes.Ldloc_0); |
| 67 | il.Emit(OpCodes.Call, typeof(ISessionFactory).GetMethod("OpenSession", new Type[0])); |
| 68 | il.Emit(OpCodes.Stloc_1); |
| 69 | |
| 70 | writeLine(il, "Saving session"); |
| 71 | il.Emit(OpCodes.Ldloc_1); |
| 72 | il.Emit(OpCodes.Stsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static)); |
| 73 | il.Emit(OpCodes.Nop); |
| 74 | |
| 75 | // transaction = BaseService._session.BeginTransaction() |
| 76 | writeLine(il, "Creating Transaction"); |
| 77 | il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static)); |
| 78 | il.Emit(OpCodes.Call, typeof(ISession).GetMethod("BeginTransaction", new Type[0])); |
| 79 | il.Emit(OpCodes.Stloc_2); |
| 80 | |
| 81 | |
| 82 | // base.{thismethod}({parameters}) |
| 83 | writeLine(il, "Calling parent"); |
| 84 | il.Emit(OpCodes.Ldarg_0); |
| 85 | UInt16 i = 1; |
| 86 | m.GetParameters().ToList().ForEach(a => { |
| 87 | il.Emit(OpCodes.Ldarg, i); |
| 88 | i++; |
| 89 | }); |
| 90 | |
| 91 | il.EmitCall(OpCodes.Call, m, new Type[0]); |
| 92 | if (!typeof(void).IsAssignableFrom(m.ReturnType)) { |
| 93 | il.Emit(OpCodes.Stloc, 4); |
| 94 | } |
| 95 | |
| 96 | // transaction.Commit(); |
| 97 | writeLine(il, "Commiting Transaction"); |
| 98 | il.Emit(OpCodes.Ldloc_2); |
| 99 | il.Emit(OpCodes.Call, typeof(ITransaction).GetMethod("Commit")); |
| 100 | |
| 101 | // } catch (Exception) { |
| 102 | il.BeginCatchBlock(typeof(Exception)); |
| 103 | il.Emit(OpCodes.Pop); |
| 104 | |
| 105 | // transaction.Commit(); |
| 106 | writeLine(il, "Rolling back Transaction"); |
| 107 | il.Emit(OpCodes.Ldloc_2); |
| 108 | il.Emit(OpCodes.Brfalse_S, transactionNull); |
| 109 | il.Emit(OpCodes.Ldloc_2); |
| 110 | il.Emit(OpCodes.Call, typeof(ITransaction).GetMethod("Rollback")); |
| 111 | writeLine(il, "Exception got!"); |
| 112 | il.MarkLabel(transactionNull); |
| 113 | il.Emit(OpCodes.Rethrow); |
| 114 | |
| 115 | |
| 116 | // } finally { |
| 117 | il.BeginFinallyBlock(); |
| 118 | // BaseService._session.Close(); |
| 119 | writeLine(il, "Closing session"); |
| 120 | il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static)); |
| 121 | il.Emit(OpCodes.Brfalse_S, exit); |
| 122 | il.Emit(OpCodes.Ldsfld, typeof(BaseService).GetField("_session", BindingFlags.NonPublic | BindingFlags.Static)); |
| 123 | il.Emit(OpCodes.Call, typeof(ISession).GetMethod("Close")); |
| 124 | il.Emit(OpCodes.Pop); |
| 125 | //} |
| 126 | il.EndExceptionBlock(); |
| 127 | |
| 128 | // return {returndata} |
| 129 | if (!typeof(void).IsAssignableFrom(m.ReturnType)) { |
| 130 | il.Emit(OpCodes.Ldloc, 4); |
| 131 | } |
| 132 | |
| 133 | il.MarkLabel(exit); |
| 134 | il.Emit(OpCodes.Ret); |
| 135 | }); |
| 136 | |
| 137 | return tb; |
| 138 | } |
| 139 | |
| 140 | private static void writeLine(ILGenerator il, string line) { |
| 141 | il.Emit(OpCodes.Ldstr, line); |
| 142 | il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 |