using System; using System.Collections.Generic; using System.Text; using System.Reflection; using System.Reflection.Emit; namespace WmData { /// /// This class provides tools to generate IL on the fly, /// it is used to generate WmIntermediateObjects that provide /// faster dynamic object access than System.Relfection. /// public class WmIntermediateObjectTools { public static CreateInstanceHandler GetInstanceCreator(Type type) { // generates a dynamic method to generate a CreateInstanceHandler delegate DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, type, new Type[0], typeof(WmIntermediateObjectTools).Module); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); // generates code to create a new object of the specified type using the default constructor ilGenerator.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); // returns the value to the caller ilGenerator.Emit(OpCodes.Ret); // converts the DynamicMethod to a CreateInstanceHandler delegate to create the object CreateInstanceHandler creator = (CreateInstanceHandler)dynamicMethod.CreateDelegate(typeof(CreateInstanceHandler)); return creator; } public static PropertyGetHandler GetPropertyGetter(PropertyInfo propInfo) { // generates a dynamic method to generate a PropertyGetHandler delegate DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object) }, propInfo.DeclaringType.Module); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); // loads the object into the stack ilGenerator.Emit(OpCodes.Ldarg_0); // calls the getter ilGenerator.EmitCall(OpCodes.Callvirt, propInfo.GetGetMethod(), null); // creates code for handling the return value EmitBoxIfNeeded(ilGenerator, propInfo.PropertyType); // returns the value to the caller ilGenerator.Emit(OpCodes.Ret); // converts the DynamicMethod to a PropertyGetHandler delegate to get the property PropertyGetHandler getter = (PropertyGetHandler)dynamicMethod.CreateDelegate(typeof(PropertyGetHandler)); return getter; } public static PropertySetHandler GetPropertySetter(PropertyInfo propInfo) { // generates a dynamic method to generate a PropertySetHandler delegate DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, null, new Type[] { typeof(object), typeof(object) }, propInfo.DeclaringType.Module); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); // loads the object into the stack ilGenerator.Emit(OpCodes.Ldarg_0); // loads the parameter from the stack ilGenerator.Emit(OpCodes.Ldarg_1); // cast to the proper type (unboxing if needed) EmitCastToReference(ilGenerator, propInfo.PropertyType); // calls the setter ilGenerator.EmitCall(OpCodes.Callvirt, propInfo.GetSetMethod(), null); // terminates the call ilGenerator.Emit(OpCodes.Ret); // converts the DynamicMethod to a PropertyGetHandler delegate to get the property PropertySetHandler setter = (PropertySetHandler)dynamicMethod.CreateDelegate(typeof(PropertySetHandler)); return setter; } /// Emits the cast to a reference, unboxing if needed. /// The MSIL generator. /// The type to cast. private static void EmitCastToReference(ILGenerator ilGenerator, System.Type type) { if (type.IsValueType) { ilGenerator.Emit(OpCodes.Unbox_Any, type); } else { ilGenerator.Emit(OpCodes.Castclass, type); } } /// Boxes a type if needed. /// The MSIL generator. /// The type. private static void EmitBoxIfNeeded(ILGenerator ilGenerator, System.Type type) { if (type.IsValueType) { ilGenerator.Emit(OpCodes.Box, type); } } /// Emits code to save an integer to the evaluation stack. /// The MSIL generator. /// The value to push. private static void EmitFastInt(ILGenerator ilGenerator, int value) { // for small integers, emit the proper opcode switch (value) { case -1: ilGenerator.Emit(OpCodes.Ldc_I4_M1); return; case 0: ilGenerator.Emit(OpCodes.Ldc_I4_0); return; case 1: ilGenerator.Emit(OpCodes.Ldc_I4_1); return; case 2: ilGenerator.Emit(OpCodes.Ldc_I4_2); return; case 3: ilGenerator.Emit(OpCodes.Ldc_I4_3); return; case 4: ilGenerator.Emit(OpCodes.Ldc_I4_4); return; case 5: ilGenerator.Emit(OpCodes.Ldc_I4_5); return; case 6: ilGenerator.Emit(OpCodes.Ldc_I4_6); return; case 7: ilGenerator.Emit(OpCodes.Ldc_I4_7); return; case 8: ilGenerator.Emit(OpCodes.Ldc_I4_8); return; } // for bigger values emit the short or long opcode if (value > -129 && value < 128) { ilGenerator.Emit(OpCodes.Ldc_I4_S, (SByte)value); } else { ilGenerator.Emit(OpCodes.Ldc_I4, value); } } } public delegate object CreateInstanceHandler(); public delegate object PropertyGetHandler(object target); public delegate void PropertySetHandler(object target, object parameter); }