I have implemented a LCG IGetSetHelper implementation. It needs to be tested (and I don't really have the time to manage it). So here it is...
Code:
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Cfg/Environment.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Cfg/Environment.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Cfg/Environment.cs (revision 92)
@@ -94,8 +94,10 @@
public const string PrepareSql = "hibernate.prepare_sql";
public const string CommandTimeout = "hibernate.command_timeout";
public const string PropertyUseReflectionOptimizer = "hibernate.use_reflection_optimizer";
+ public const string PropertyUseLightweightCodeGeneration = "hibernate.use_lightweight_code_generation";
private static bool EnableReflectionOptimizer;
+ private static bool EnableLightweightCodeGeneration;
private static IDictionary GlobalProperties;
@@ -191,5 +193,14 @@
get { return EnableReflectionOptimizer; }
set { EnableReflectionOptimizer = value; }
}
+
+ /// <summary>
+ /// Enables the use of .NET 2.0 LCG techniques within the reflection optimizer.
+ /// </summary>
+ public static bool UseLightweightCodeGeneration
+ {
+ get { return EnableLightweightCodeGeneration; }
+ set { EnableLightweightCodeGeneration = value; }
+ }
}
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/ISetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/ISetter.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/ISetter.cs (revision 92)
@@ -40,5 +40,16 @@
/// <id> property.
/// </remarks>
PropertyInfo Property { get; }
+
+ /// <summary>
+ /// Gets the member info of the underlying member that this getter wraps.
+ /// Should return null when not implemented.
+ /// </summary>
+ MemberInfo Member { get; }
+
+ /// <summary>
+ /// Gets the type of the property/field.
+ /// </summary>
+ System.Type ValueType { get; }
}
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicGetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicGetter.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicGetter.cs (revision 92)
@@ -75,6 +75,10 @@
get { return property; }
}
+ public MemberInfo Member
+ {
+ get { return property; }
+ }
#endregion
}
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldGetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldGetter.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldGetter.cs (revision 92)
@@ -73,6 +73,10 @@
get { return null; }
}
+ public MemberInfo Member
+ {
+ get { return field; }
+ }
#endregion
}
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/IGetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/IGetter.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/IGetter.cs (revision 92)
@@ -48,5 +48,11 @@
/// <id> property.
/// </remarks>
PropertyInfo Property { get; }
+
+ /// <summary>
+ /// Gets the member info of the underlying member that this getter wraps.
+ /// Should return null when not implemented.
+ /// </summary>
+ MemberInfo Member { get; }
}
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicSetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicSetter.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/BasicSetter.cs (revision 92)
@@ -81,6 +81,15 @@
get { return property; }
}
+ public MemberInfo Member
+ {
+ get { return property; }
+ }
+
+ public System.Type ValueType
+ {
+ get { return property.PropertyType; }
+ }
#endregion
}
}
\ No newline at end of file
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldSetter.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldSetter.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Property/FieldSetter.cs (revision 92)
@@ -81,6 +81,15 @@
get { return null; }
}
+ public MemberInfo Member
+ {
+ get { return field; }
+ }
+
+ public System.Type ValueType
+ {
+ get { return field.FieldType; }
+ }
#endregion
}
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/LCGGetSetHelper.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/LCGGetSetHelper.cs (revision 0)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/LCGGetSetHelper.cs (revision 92)
@@ -0,0 +1,243 @@
+using System;
+using System.CodeDom.Compiler;
+using System.Globalization;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using log4net;
+using NHibernate.Property;
+
+namespace NHibernate.Persister
+{
+ class LCGGetSetHelper : IGetSetHelper
+ {
+ private delegate void SetPropertyValuesInvoker(object o,object[] values);
+ private delegate object[] GetPropertyValuesInvoker(object o);
+
+ private SetPropertyValuesInvoker m_Setter;
+ private GetPropertyValuesInvoker m_Getter;
+
+ private static readonly ILog m_Log = LogManager.GetLogger(typeof(LCGGetSetHelper));
+
+ /// <summary>
+ /// Class constructor.
+ /// </summary>
+ /// <param name="mappedClass"></param>
+ /// <param name="setters"></param>
+ /// <param name="getters"></param>
+ public LCGGetSetHelper(System.Type mappedClass, ISetter[] setters, IGetter[] getters)
+ {
+ //Generate the set and get dynamic methods
+ m_Setter = GenerateSetPropertyValuesMethod(mappedClass, setters);
+ m_Getter = GenerateGetPropertyValuesMethod(mappedClass, getters);
+ }
+
+ /// <summary>
+ /// Generates a dynamic method on the given type.
+ /// </summary>
+ /// <param name="mappedClass"></param>
+ /// <param name="getters"></param>
+ /// <returns></returns>
+ private static GetPropertyValuesInvoker GenerateGetPropertyValuesMethod(System.Type mappedClass, IGetter[] getters)
+ {
+ DynamicMethod method = new DynamicMethod(
+ String.Empty,
+ typeof(object[]),
+ new System.Type[] { typeof(object) },
+ mappedClass,
+ true);
+
+ ILGenerator il = method.GetILGenerator();
+
+ // Declare the locals
+ LocalBuilder dataLocal = il.DeclareLocal(typeof(Object[]));
+ LocalBuilder thisLocal = il.DeclareLocal(mappedClass);
+
+ // Set the this local
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Stloc, thisLocal.LocalIndex);
+
+ // Allocate the data array
+ il.Emit(OpCodes.Ldc_I4, getters.Length);
+ il.Emit(OpCodes.Newarr, typeof(Object));
+ il.Emit(OpCodes.Stloc, dataLocal.LocalIndex);
+
+ //get all the data from the object into the data array to be returned
+ for (int i = 0; i < getters.Length; i++)
+ {
+ // get the member accessors
+ IGetter getter = getters[i];
+ if (getter.Member != null)
+ {
+ // get the data element location
+ il.Emit(OpCodes.Ldloc, dataLocal.LocalIndex);
+ il.Emit(OpCodes.Ldc_I4, i);
+
+ // get the value
+ il.Emit((mappedClass.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc), thisLocal.LocalIndex);
+ switch (getter.Member.MemberType)
+ {
+ // fields...
+ case MemberTypes.Field:
+ FieldInfo fieldInfo = ((FieldInfo)getter.Member);
+ il.Emit(OpCodes.Ldfld, fieldInfo);
+ break;
+
+ // properties...
+ case MemberTypes.Property:
+ MethodInfo methodInfo = ((PropertyInfo)getter.Member).GetGetMethod(true);
+ if (methodInfo != null)
+ {
+ if (methodInfo.IsVirtual)
+ {
+ il.Emit(OpCodes.Callvirt, methodInfo);
+ }
+ else
+ {
+ il.Emit(OpCodes.Call, methodInfo);
+ }
+ }
+ else
+ {
+ m_Log.InfoFormat("Property {0} is marked write-only. Retrieving null value.", getter.PropertyName);
+ il.Emit(OpCodes.Pop);
+ il.Emit(OpCodes.Ldnull);
+ }
+ break;
+
+ // uh-oh!
+ default:
+ throw new NHibernate.HibernateException("Unhandled member type!");
+ }
+
+ // box the value?
+ if (getter.ReturnType.IsValueType)
+ {
+ il.Emit(OpCodes.Box, getter.ReturnType);
+ }
+ }
+ else
+ {
+ throw new NHibernate.HibernateException("IGetter implementation does not implement the required Member property!");
+ }
+
+ //store the value
+ il.Emit(OpCodes.Stelem_Ref);
+ }
+
+ // Return the data array
+ il.Emit(OpCodes.Ldloc, dataLocal.LocalIndex);
+ il.Emit(OpCodes.Ret);
+
+ return (GetPropertyValuesInvoker)method.CreateDelegate(typeof(GetPropertyValuesInvoker));
+ }
+
+ /// <summary>
+ /// Generates a dynamic method on the given type.
+ /// </summary>
+ /// <param name="mappedClass"></param>
+ /// <param name="setters"></param>
+ /// <returns></returns>
+ private static SetPropertyValuesInvoker GenerateSetPropertyValuesMethod(System.Type mappedClass, ISetter[] setters)
+ {
+ DynamicMethod method = new DynamicMethod(
+ String.Empty,
+ typeof(void),
+ new System.Type[] { typeof(object), typeof(object[]) },
+ mappedClass,
+ true);
+
+ ILGenerator il = method.GetILGenerator();
+
+ // Declare a local variable used to store the object reference (typed)
+ LocalBuilder thisLocal = il.DeclareLocal(mappedClass);
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Stloc, thisLocal.LocalIndex);
+
+ for (int i = 0; i < setters.Length; i++)
+ {
+ // get the member accessor
+ ISetter setter = setters[i];
+ if (setter.Member != null)
+ {
+ // load the this pointer
+ il.Emit((mappedClass.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc), thisLocal.LocalIndex);
+
+ // load the value
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Ldc_I4, i);
+ il.Emit(OpCodes.Ldelem_Ref);
+
+ // cast and optionly unbox the value
+ il.Emit(OpCodes.Unbox_Any, setter.ValueType);
+
+ // set the value
+ switch (setter.Member.MemberType)
+ {
+ // fields...
+ case MemberTypes.Field:
+ il.Emit(OpCodes.Stfld, (FieldInfo)setter.Member);
+ break;
+
+ // properties...
+ case MemberTypes.Property:
+ MethodInfo methodInfo = ((PropertyInfo)setter.Member).GetSetMethod(true);
+ if (methodInfo != null)
+ {
+ if (methodInfo.IsVirtual)
+ {
+ il.Emit(OpCodes.Callvirt, methodInfo);
+ }
+ else
+ {
+ il.Emit(OpCodes.Call, methodInfo);
+ }
+ }
+ else
+ {
+ m_Log.InfoFormat("Property {0} is marked read-only. Ignoring property value.", setter.PropertyName);
+ il.Emit(OpCodes.Pop);
+ il.Emit(OpCodes.Pop);
+ }
+ break;
+
+ // uh-oh!
+ default:
+ throw new NHibernate.HibernateException("Unhandled member type!");
+ }
+ }
+ else
+ {
+ throw new NHibernate.HibernateException("ISetter implementation does not implement the required Member property!");
+ }
+ }
+
+ // Setup the return
+ il.Emit(OpCodes.Ret);
+
+ return (SetPropertyValuesInvoker)method.CreateDelegate(typeof(SetPropertyValuesInvoker));
+ }
+
+ /// <summary>
+ /// Sets the property values.
+ /// </summary>
+ /// <param name="o"></param>
+ /// <param name="values"></param>
+ public void SetPropertyValues(object o, object[] values)
+ {
+ m_Setter(o, values);
+ }
+
+ /// <summary>
+ /// Gets the property values.
+ /// </summary>
+ /// <param name="o"></param>
+ /// <returns></returns>
+ public object[] GetPropertyValues(object o)
+ {
+ return m_Getter(o);
+ }
+
+ }
+}
Index: D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/GetSetHelperFactory.cs
===================================================================
--- D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/GetSetHelperFactory.cs (revision 90)
+++ D:/Acme/3rdParty/NHibernate/1.0.2.0/Support/src/NHibernate/Persister/GetSetHelperFactory.cs (revision 92)
@@ -53,16 +53,23 @@
/// <param name="setters">Array of setters</param>
/// <param name="getters">Array of getters</param>
/// <returns>null if the generation fail</returns>
- public static IGetSetHelper Create( System.Type mappedClass, ISetter[] setters, IGetter[] getters )
- {
- if (mappedClass.IsValueType)
- {
- // Cannot create optimizer for value types - the setter method will not work.
- log.Info( "Disabling reflection optimizer for value type " + mappedClass.FullName );
- return null;
- }
- return new GetSetHelperFactory( mappedClass, setters, getters ).CreateGetSetHelper();
- }
+ public static IGetSetHelper Create(System.Type mappedClass, ISetter[] setters, IGetter[] getters)
+ {
+ if (!Cfg.Environment.UseLightweightCodeGeneration)
+ {
+ if (mappedClass.IsValueType)
+ {
+ // Cannot create optimizer for value types - the setter method will not work.
+ log.Info("Disabling reflection optimizer for value type " + mappedClass.FullName);
+ return null;
+ }
+ return new GetSetHelperFactory(mappedClass, setters, getters).CreateGetSetHelper();
+ }
+ else
+ {
+ return new LCGGetSetHelper(mappedClass, setters, getters);
+ }
+ }
private IGetSetHelper CreateGetSetHelper()
{