From 86ee2fbbb29ca4783273d24e4c853c96580c5627 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 25 Dec 2012 22:35:12 -0300 Subject: [PATCH] Updated codebase to support medium trust: - changes some 'object' references to 'Delegate' (easier to understand) - changes MultiPocoFactory class to perform the operation of calling the callback and calling each mapper delegate - changes CreateMultiPocoFactory, this is the problem with medium trust... you cannot declare a DynamicMethod with an 'owner' in medium trust. Also, there there is no need for any of the IL.Emit logic in this method and therefore no need for the DynamicMethod at all in this method. It has been changed so that the MultiPocoFactory class does the heavy lifting. Without a DynamicMethod or IL Emit, this should work a teeny bit faster and is much easier to debug. Before I realized that the IL Emit was not necessary, i did make it work in medium trust with IL Emit so have saved that code locally in case its required. --- PetaPoco/PetaPoco.cs | 101 ++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/PetaPoco/PetaPoco.cs b/PetaPoco/PetaPoco.cs index 84e00048..ef9645f1 100644 --- a/PetaPoco/PetaPoco.cs +++ b/PetaPoco/PetaPoco.cs @@ -841,7 +841,7 @@ public IEnumerable Query(string sql, params object[] args) public IEnumerable Query(Sql sql) { return Query(new Type[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, null, sql.SQL, sql.Arguments); } // Automagically guess the property relationships between various POCOs and create a delegate that will set them up - object GetAutoMapper(Type[] types) + Delegate GetAutoMapper(Type[] types) { // Build a key var kb = new StringBuilder(); @@ -856,7 +856,7 @@ object GetAutoMapper(Type[] types) RWLock.EnterReadLock(); try { - object mapper; + Delegate mapper; if (AutoMappers.TryGetValue(key, out mapper)) return mapper; } @@ -870,7 +870,7 @@ object GetAutoMapper(Type[] types) try { // Try again - object mapper; + Delegate mapper; if (AutoMappers.TryGetValue(key, out mapper)) return mapper; @@ -946,19 +946,49 @@ Delegate FindSplitPoint(Type typeThis, Type typeNext, string sql, IDataReader r, // Instance data used by the Multipoco factory delegate - essentially a list of the nested poco factories to call class MultiPocoFactory { - public List m_Delegates; - public Delegate GetItem(int index) { return m_Delegates[index]; } + + public MultiPocoFactory(IEnumerable dels) + { + Delegates = new List(dels); + } + private List Delegates { get; set; } + private Delegate GetItem(int index) { return Delegates[index]; } + + /// + /// Calls the delegate at the specified index and returns its values + /// + /// + /// + /// + private object CallDelegate(int index, IDataReader reader) + { + var d = GetItem(index); + var output = d.DynamicInvoke(reader); + return output; + } + + /// + /// Calls the callback delegate and passes in the output of all delegates as the parameters + /// + /// + /// + /// + /// + /// + public TRet CallCallback(Delegate callback, IDataReader dr, int count) + { + var args = new List(); + for(var i = 0;i CreateMultiPocoFactory(Type[] types, string sql, IDataReader r) - { - var m = new DynamicMethod("petapoco_multipoco_factory", typeof(TRet), new Type[] { typeof(MultiPocoFactory), typeof(IDataReader), typeof(object) }, typeof(MultiPocoFactory)); - var il = m.GetILGenerator(); - - // Load the callback - il.Emit(OpCodes.Ldarg_2); - + Func CreateMultiPocoFactory(Type[] types, string sql, IDataReader r) + { // Call each delegate var dels = new List(); int pos = 0; @@ -967,33 +997,19 @@ Func CreateMultiPocoFactory(Type[] types, strin // Add to list of delegates to call var del = FindSplitPoint(types[i], i + 1 < types.Length ? types[i + 1] : null, sql, r, ref pos); dels.Add(del); - - // Get the delegate - il.Emit(OpCodes.Ldarg_0); // callback,this - il.Emit(OpCodes.Ldc_I4, i); // callback,this,Index - il.Emit(OpCodes.Callvirt, typeof(MultiPocoFactory).GetMethod("GetItem")); // callback,Delegate - il.Emit(OpCodes.Ldarg_1); // callback,delegate, datareader - - // Call Invoke - var tDelInvoke = del.GetType().GetMethod("Invoke"); - il.Emit(OpCodes.Callvirt, tDelInvoke); // Poco left on stack } - // By now we should have the callback and the N pocos all on the stack. Call the callback and we're done - il.Emit(OpCodes.Callvirt, Expression.GetFuncType(types.Concat(new Type[] { typeof(TRet) }).ToArray()).GetMethod("Invoke")); - il.Emit(OpCodes.Ret); - - // Finish up - return (Func)m.CreateDelegate(typeof(Func), new MultiPocoFactory() { m_Delegates = dels }); + var mpFactory = new MultiPocoFactory(dels); + return (reader, arg3) => mpFactory.CallCallback(arg3, reader, types.Length); } // Various cached stuff static Dictionary MultiPocoFactories = new Dictionary(); - static Dictionary AutoMappers = new Dictionary(); + static Dictionary AutoMappers = new Dictionary(); static System.Threading.ReaderWriterLockSlim RWLock = new System.Threading.ReaderWriterLockSlim(); - // Get (or create) the multi-poco factory for a query - Func GetMultiPocoFactory(Type[] types, string sql, IDataReader r) + // Get (or create) the multi-poco factory for a query + Func GetMultiPocoFactory(Type[] types, string sql, IDataReader r) { // Build a key string (this is crap, should address this at some point) var kb = new StringBuilder(); @@ -1015,7 +1031,10 @@ Func GetMultiPocoFactory(Type[] types, string s { object oFactory; if (MultiPocoFactories.TryGetValue(key, out oFactory)) - return (Func)oFactory; + { + //mpFactory = oFactory; + return (Func)oFactory; + } } finally { @@ -1029,13 +1048,15 @@ Func GetMultiPocoFactory(Type[] types, string s // Check again object oFactory; if (MultiPocoFactories.TryGetValue(key, out oFactory)) - return (Func)oFactory; - - // Create the factory - var Factory = CreateMultiPocoFactory(types, sql, r); + { + return (Func)oFactory; + } + + // Create the factory + var factory = CreateMultiPocoFactory(types, sql, r); - MultiPocoFactories.Add(key, Factory); - return Factory; + MultiPocoFactories.Add(key, factory); + return factory; } finally { @@ -1045,7 +1066,7 @@ Func GetMultiPocoFactory(Type[] types, string s } // Actual implementation of the multi-poco query - public IEnumerable Query(Type[] types, object cb, string sql, params object[] args) + public IEnumerable Query(Type[] types, Delegate cb, string sql, params object[] args) { OpenSharedConnection(); try