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);
}