|
From: <sm...@us...> - 2003-08-13 20:09:04
|
Update of /cvsroot/nmock/nmock/src/NMock/Dynamic
In directory sc8-pr-cvs1:/tmp/cvs-serv30014/src/NMock/Dynamic
Modified Files:
ClassGenerator.cs
Log Message:
Added IInvocationHandler and generalised DynamicProxy generation
(with Jon Tirsen)
Index: ClassGenerator.cs
===================================================================
RCS file: /cvsroot/nmock/nmock/src/NMock/Dynamic/ClassGenerator.cs,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** ClassGenerator.cs 25 Jul 2003 15:52:12 -0000 1.14
--- ClassGenerator.cs 13 Aug 2003 19:42:39 -0000 1.15
***************
*** 9,27 ****
public class ClassGenerator
{
! internal const System.Reflection.BindingFlags ALL_INSTANCE_METHODS
! = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
! public virtual object Generate(Type type, IMock mock)
{
! return Generate(type, mock, new ArrayList());
}
! public virtual object Generate(Type type, IMock mock, IList methodsToIgnore)
{
methodsToIgnore.Add("Equals");
methodsToIgnore.Add("ToString");
! TypeBuilder typeBuilder = GetTypeBuilder("Mock" + type.Name, type);
! MethodImplementor methodImplementor = new MethodImplementor(typeBuilder);
foreach (Type currentType in new InterfaceLister().List(type))
--- 9,31 ----
public class ClassGenerator
{
! public static readonly string INVOCATION_HANDLER_FIELD_NAME = "_invocationHandler";
! internal const System.Reflection.BindingFlags ALL_INSTANCE_METHODS
! = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
!
! public virtual object Generate(Type type, IInvocationHandler handler)
{
! return Generate(type, handler, new ArrayList());
}
! public virtual object Generate(Type type, IInvocationHandler handler, IList methodsToIgnore)
{
methodsToIgnore.Add("Equals");
methodsToIgnore.Add("ToString");
! TypeBuilder typeBuilder = GetTypeBuilder("Proxy" + type.Name, type);
! MethodImplementor methodImplementor = new MethodImplementor(typeBuilder,
! typeBuilder.DefineField(ClassGenerator.INVOCATION_HANDLER_FIELD_NAME,
! typeof(IInvocationHandler), FieldAttributes.Public));
foreach (Type currentType in new InterfaceLister().List(type))
***************
*** 35,44 ****
}
}
! return CreateProxyInstance(typeBuilder, mock);
}
bool ShouldImplement(MethodInfo methodInfo, IList methodsToIgnore)
{
! if (!methodInfo.IsVirtual || methodInfo.IsFinal) {
methodsToIgnore.Add(methodInfo.Name);
}
--- 39,49 ----
}
}
! return CreateProxyInstance(typeBuilder, handler);
}
bool ShouldImplement(MethodInfo methodInfo, IList methodsToIgnore)
{
! if (!methodInfo.IsVirtual || methodInfo.IsFinal)
! {
methodsToIgnore.Add(methodInfo.Name);
}
***************
*** 50,54 ****
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName assemblyName = new AssemblyName();
! assemblyName.Name = "DynamicMockAssembly";
AssemblyBuilder assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MockModule");
--- 55,59 ----
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName assemblyName = new AssemblyName();
! assemblyName.Name = "DynamicProxyAssembly";
AssemblyBuilder assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MockModule");
***************
*** 66,233 ****
}
! object CreateProxyInstance(TypeBuilder typeBuilder, IMock mock)
! {
! Type proxyType = typeBuilder.CreateType();
! object result = Activator.CreateInstance(proxyType);
! FieldInfo underlyingMock = proxyType.GetField("underlyingMock");
! underlyingMock.SetValue(result, mock);
! return result;
! }
}
! public class MethodImplementor
! {
! private BoxingOpCodes boxingOpCodes = new BoxingOpCodes();
! private TypeBuilder typeBuilder;
! private FieldBuilder mockFieldBuilder;
! public MethodImplementor(TypeBuilder aTypeBuilder)
! {
! typeBuilder = aTypeBuilder;
! mockFieldBuilder = typeBuilder.DefineField("underlyingMock", typeof(IMock), FieldAttributes.Public);
! }
! public virtual void Implement(MethodInfo methodInfo)
! {
! Type returnType = methodInfo.ReturnType;
! ParameterInfo[] parameterInfo = methodInfo.GetParameters();
! Type[] paramTypes = ExtractParameterTypes(parameterInfo);
! ILGenerator il = CreateILGenerator(methodInfo, returnType, paramTypes);
! EmitMethodSignature(methodInfo, paramTypes, il);
! EmitMethodCall(il);
! EmitMethodReturn(returnType, il);
! }
! private Type[] ExtractParameterTypes(ParameterInfo[] parameters)
! {
! Type[] paramTypes = new Type[parameters.Length];
! for (int i = 0; i < parameters.Length; ++i)
! {
! paramTypes[i] = parameters[i].ParameterType;
! }
! return paramTypes;
! }
! private ILGenerator CreateILGenerator(MethodInfo methodInfo, Type returnType, Type[] paramTypes)
! {
! MethodBuilder methodBuilder =
! typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, returnType, paramTypes);
! return methodBuilder.GetILGenerator();
! }
! private void EmitMethodSignature(MethodInfo methodInfo, Type[] paramTypes, ILGenerator il)
! {
il.DeclareLocal( typeof(object) );
! il.Emit(OpCodes.Ldarg_0);
! il.Emit(OpCodes.Ldfld, mockFieldBuilder);
! il.Emit(OpCodes.Ldstr, StripGetSetPrefix(methodInfo));
! il.Emit(OpCodes.Ldc_I4_S, paramTypes.Length);
! il.Emit(OpCodes.Newarr, typeof(object));
! if (paramTypes.Length > 0)
! {
! il.Emit(OpCodes.Stloc_0);
! il.Emit(OpCodes.Ldloc_0);
! for(int i = 0; i < paramTypes.Length; i++)
! {
! il.Emit(OpCodes.Ldc_I4_S, i);
! il.Emit(OpCodes.Ldarg_S, i + 1);
! if (paramTypes[i].IsPrimitive || paramTypes[i].IsValueType)
! {
! il.Emit(OpCodes.Box, paramTypes[i]);
! }
! il.Emit(OpCodes.Stelem_Ref);
! il.Emit(OpCodes.Ldloc_0);
! }
! }
! }
! private void EmitMethodCall(ILGenerator il)
! {
! MethodInfo call = typeof(IMock).GetMethod("Call");
! il.EmitCall(OpCodes.Callvirt, call, null);
! }
! private void EmitMethodReturn(Type returnType, ILGenerator il)
! {
! if (returnType == typeof(void))
! {
! il.Emit(OpCodes.Pop);
! }
! else
! {
! if (returnType.IsPrimitive || returnType.IsEnum)
! {
! il.Emit(OpCodes.Unbox, returnType);
! il.Emit(boxingOpCodes[returnType]);
! }
! il.DeclareLocal(returnType);
! il.Emit(OpCodes.Stloc_1);
! Label l = il.DefineLabel();
! il.Emit(OpCodes.Br_S, l);
! il.MarkLabel(l);
! il.Emit(OpCodes.Ldloc_1);
! }
! il.Emit(OpCodes.Ret);
! }
! private string StripGetSetPrefix(MethodInfo methodInfo)
! {
! string methodName;
! methodName = methodInfo.Name;
! if (methodName.StartsWith("get_") || methodName.StartsWith("set_"))
! {
! methodName = methodName.Substring(4);
! }
! return methodName;
! }
! }
! public class BoxingOpCodes
! {
! private static IDictionary boxingOpCodes;
! public OpCode this[Type aType]
! {
! get
! {
! return GetOpCode(aType);
! }
! }
! private static OpCode GetOpCode( Type aType )
! {
! if (boxingOpCodes == null)
! {
! boxingOpCodes = new Hashtable();
! boxingOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1;
! boxingOpCodes[typeof(short)] = OpCodes.Ldind_I2;
! boxingOpCodes[typeof(int)] = OpCodes.Ldind_I4;
! boxingOpCodes[typeof(long)] = OpCodes.Ldind_I8;
! boxingOpCodes[typeof(byte)] = OpCodes.Ldind_U1;
! boxingOpCodes[typeof(ushort)] = OpCodes.Ldind_U2;
! boxingOpCodes[typeof(uint)] = OpCodes.Ldind_U4;
! boxingOpCodes[typeof(ulong)] = OpCodes.Ldind_I8;
! boxingOpCodes[typeof(float)] = OpCodes.Ldind_R4;
! boxingOpCodes[typeof(double)] = OpCodes.Ldind_R8;
! boxingOpCodes[typeof(char)] = OpCodes.Ldind_U2;
! boxingOpCodes[typeof(bool)] = OpCodes.Ldind_I1;
! }
! if (boxingOpCodes.Contains(aType))
! {
! return (OpCode)boxingOpCodes[aType];
! }
! else
! {
! return OpCodes.Ldind_I1;
! }
! }
! }
}
--- 71,238 ----
}
! object CreateProxyInstance(TypeBuilder typeBuilder, IInvocationHandler handler)
! {
! Type proxyType = typeBuilder.CreateType();
! object result = Activator.CreateInstance(proxyType);
! FieldInfo handlerField = proxyType.GetField(INVOCATION_HANDLER_FIELD_NAME);
! handlerField.SetValue(result, handler);
! return result;
! }
}
! public class MethodImplementor
! {
! private BoxingOpCodes boxingOpCodes = new BoxingOpCodes();
! private TypeBuilder typeBuilder;
! private FieldBuilder handlerFieldBuilder;
! public MethodImplementor(TypeBuilder aTypeBuilder, FieldBuilder handlerFieldBuilder)
! {
! typeBuilder = aTypeBuilder;
! this.handlerFieldBuilder = handlerFieldBuilder;
! }
! public virtual void Implement(MethodInfo methodInfo)
! {
! Type returnType = methodInfo.ReturnType;
! ParameterInfo[] parameterInfo = methodInfo.GetParameters();
! Type[] paramTypes = ExtractParameterTypes(parameterInfo);
! ILGenerator il = CreateILGenerator(methodInfo, returnType, paramTypes);
! EmitMethodSignature(methodInfo, paramTypes, il);
! EmitMethodCall(il);
! EmitMethodReturn(returnType, il);
! }
! private Type[] ExtractParameterTypes(ParameterInfo[] parameters)
! {
! Type[] paramTypes = new Type[parameters.Length];
! for (int i = 0; i < parameters.Length; ++i)
! {
! paramTypes[i] = parameters[i].ParameterType;
! }
! return paramTypes;
! }
! private ILGenerator CreateILGenerator(MethodInfo methodInfo, Type returnType, Type[] paramTypes)
! {
! MethodBuilder methodBuilder =
! typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, returnType, paramTypes);
! return methodBuilder.GetILGenerator();
! }
! private void EmitMethodSignature(MethodInfo methodInfo, Type[] paramTypes, ILGenerator il)
! {
il.DeclareLocal( typeof(object) );
! il.Emit(OpCodes.Ldarg_0);
! il.Emit(OpCodes.Ldfld, handlerFieldBuilder);
! il.Emit(OpCodes.Ldstr, StripGetSetPrefix(methodInfo));
! il.Emit(OpCodes.Ldc_I4_S, paramTypes.Length);
! il.Emit(OpCodes.Newarr, typeof(object));
! if (paramTypes.Length > 0)
! {
! il.Emit(OpCodes.Stloc_0);
! il.Emit(OpCodes.Ldloc_0);
! for(int i = 0; i < paramTypes.Length; i++)
! {
! il.Emit(OpCodes.Ldc_I4_S, i);
! il.Emit(OpCodes.Ldarg_S, i + 1);
! if (paramTypes[i].IsPrimitive || paramTypes[i].IsValueType)
! {
! il.Emit(OpCodes.Box, paramTypes[i]);
! }
! il.Emit(OpCodes.Stelem_Ref);
! il.Emit(OpCodes.Ldloc_0);
! }
! }
! }
! private void EmitMethodCall(ILGenerator il)
! {
! MethodInfo call = typeof(IInvocationHandler).GetMethod("Call");
! il.EmitCall(OpCodes.Callvirt, call, null);
! }
! private void EmitMethodReturn(Type returnType, ILGenerator il)
! {
! if (returnType == typeof(void))
! {
! il.Emit(OpCodes.Pop);
! }
! else
! {
! if (returnType.IsPrimitive || returnType.IsEnum)
! {
! il.Emit(OpCodes.Unbox, returnType);
! il.Emit(boxingOpCodes[returnType]);
! }
! il.DeclareLocal(returnType);
! il.Emit(OpCodes.Stloc_1);
! Label l = il.DefineLabel();
! il.Emit(OpCodes.Br_S, l);
! il.MarkLabel(l);
! il.Emit(OpCodes.Ldloc_1);
! }
! il.Emit(OpCodes.Ret);
! }
! private string StripGetSetPrefix(MethodInfo methodInfo)
! {
! string methodName;
! methodName = methodInfo.Name;
! if (methodName.StartsWith("get_") || methodName.StartsWith("set_"))
! {
! methodName = methodName.Substring(4);
! }
! return methodName;
! }
! }
! public class BoxingOpCodes
! {
! private static IDictionary boxingOpCodes;
! public OpCode this[Type aType]
! {
! get
! {
! return GetOpCode(aType);
! }
! }
! private static OpCode GetOpCode( Type aType )
! {
! if (boxingOpCodes == null)
! {
! boxingOpCodes = new Hashtable();
! boxingOpCodes[typeof(sbyte)] = OpCodes.Ldind_I1;
! boxingOpCodes[typeof(short)] = OpCodes.Ldind_I2;
! boxingOpCodes[typeof(int)] = OpCodes.Ldind_I4;
! boxingOpCodes[typeof(long)] = OpCodes.Ldind_I8;
! boxingOpCodes[typeof(byte)] = OpCodes.Ldind_U1;
! boxingOpCodes[typeof(ushort)] = OpCodes.Ldind_U2;
! boxingOpCodes[typeof(uint)] = OpCodes.Ldind_U4;
! boxingOpCodes[typeof(ulong)] = OpCodes.Ldind_I8;
! boxingOpCodes[typeof(float)] = OpCodes.Ldind_R4;
! boxingOpCodes[typeof(double)] = OpCodes.Ldind_R8;
! boxingOpCodes[typeof(char)] = OpCodes.Ldind_U2;
! boxingOpCodes[typeof(bool)] = OpCodes.Ldind_I1;
! }
! if (boxingOpCodes.Contains(aType))
! {
! return (OpCode)boxingOpCodes[aType];
! }
! else
! {
! return OpCodes.Ldind_I1;
! }
! }
! }
}
|