public void NestedInterface() { ClassEmitter outerEmitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "IOuter", null, Type.EmptyTypes, TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.Public, false); NestedClassEmitter innerEmitter = new NestedClassEmitter(outerEmitter, "IInner", TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.NestedPublic, null, Type.EmptyTypes); innerEmitter.CreateMethod("MyMethod", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, typeof(void), Type.EmptyTypes); Type inner = innerEmitter.BuildType(); Type outer = outerEmitter.BuildType(); Assert.IsTrue(inner.IsInterface); MethodInfo method = inner.GetMethod("MyMethod"); Assert.IsNotNull(method); Assert.AreSame(inner, outer.GetNestedType("IInner", BindingFlags.Public)); }
protected void CreateIInvocationInvokeOnTarget( ClassEmitter targetTypeEmitter, NestedClassEmitter nested, ParameterInfo[] parameters, FieldReference targetField, MethodInfo callbackMethod) { const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual; MethodEmitter method = nested.CreateMethod ("InvokeMethodOnTarget", methodAtts, typeof (void)); Expression[] args = new Expression[parameters.Length]; // Idea: instead of grab parameters one by one // we should grab an array Hashtable byRefArguments = new Hashtable(); for(int i = 0; i < parameters.Length; i++) { ParameterInfo param = parameters[i]; Type paramType = param.ParameterType; if (HasGenericParameters(paramType)) { paramType = paramType.GetGenericTypeDefinition().MakeGenericType(nested.GetGenericArgumentsFor(paramType)); } else if (paramType.IsGenericParameter) { paramType = nested.GetGenericArgument(paramType.Name); } if (paramType.IsByRef) { LocalReference localReference = method.CodeBuilder.DeclareLocal(paramType.GetElementType()); method.CodeBuilder.AddStatement( new AssignStatement(localReference, new ConvertExpression(paramType.GetElementType(), new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod( "GetArgumentValue"), new LiteralIntExpression(i))))); ByRefReference byRefReference = new ByRefReference(localReference); args[i] = new ReferenceExpression(byRefReference); byRefArguments[i] = localReference; } else { args[i] = new ConvertExpression(paramType, new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod("GetArgumentValue"), new LiteralIntExpression(i))); } } MethodInvocationExpression baseMethodInvExp; if (callbackMethod.IsGenericMethod) { callbackMethod = callbackMethod.MakeGenericMethod(nested.GetGenericArgumentsFor(callbackMethod)); } baseMethodInvExp = new MethodInvocationExpression(targetField, callbackMethod, args); baseMethodInvExp.VirtualCall = true; LocalReference ret_local = null; if (callbackMethod.ReturnType != typeof(void)) { if (callbackMethod.ReturnType.IsGenericParameter) { ret_local = method.CodeBuilder.DeclareLocal(nested.GetGenericArgument(callbackMethod.ReturnType.Name)); } else if (HasGenericParameters(callbackMethod.ReturnType)) { ret_local = method.CodeBuilder.DeclareLocal( callbackMethod.ReturnType.GetGenericTypeDefinition().MakeGenericType( nested.GetGenericArgumentsFor(callbackMethod.ReturnType))); } else { ret_local = method.CodeBuilder.DeclareLocal(callbackMethod.ReturnType); } method.CodeBuilder.AddStatement(new AssignStatement(ret_local, baseMethodInvExp)); } else { method.CodeBuilder.AddStatement(new ExpressionStatement(baseMethodInvExp)); } foreach(DictionaryEntry byRefArgument in byRefArguments) { int index = (int) byRefArgument.Key; LocalReference localReference = (LocalReference) byRefArgument.Value; method.CodeBuilder.AddStatement( new ExpressionStatement( new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod("SetArgumentValue"), new LiteralIntExpression(index), new ConvertExpression(typeof(object), localReference.Type, new ReferenceExpression(localReference))) )); } if (callbackMethod.ReturnType != typeof(void)) { MethodInvocationExpression setRetVal = new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod("set_ReturnValue"), new ConvertExpression(typeof(object), ret_local.Type, ret_local.ToExpression())); method.CodeBuilder.AddStatement(new ExpressionStatement(setRetVal)); } method.CodeBuilder.AddStatement(new ReturnStatement()); }
protected void CreateEmptyIInvocationInvokeOnTarget(NestedClassEmitter nested) { const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual; MethodEmitter method = nested.CreateMethod("InvokeMethodOnTarget", methodAtts, typeof(void)); // TODO: throw exception String message = String.Format("This is a DynamicProxy2 error: the interceptor attempted " + "to 'Proceed' for a method without a target, for example, an interface method or an abstract method"); method.CodeBuilder.AddStatement(new ThrowStatement(typeof(NotImplementedException), message)); method.CodeBuilder.AddStatement(new ReturnStatement()); }
/// <summary> /// If callbackMethod is null the InvokeOnTarget implementation /// is just the code to throw an exception /// </summary> /// <param name="emitter"></param> /// <param name="targetType"></param> /// <param name="targetForInvocation"></param> /// <param name="methodInfo"></param> /// <param name="callbackMethod"></param> /// <param name="version"></param> /// <param name="allowChangeTarget">If true the invocation will implement the IChangeProxyTarget interface</param> /// <returns></returns> protected NestedClassEmitter BuildInvocationNestedType( ClassEmitter emitter, Type targetType, Type targetForInvocation, MethodInfo methodInfo, MethodInfo callbackMethod, ConstructorVersion version, bool allowChangeTarget) { CheckNotGenericTypeDefinition(targetType, "targetType"); CheckNotGenericTypeDefinition(targetForInvocation, "targetForInvocation"); nestedCounter++; Type[] interfaces = new Type[0]; if (allowChangeTarget) { interfaces = new Type[] {typeof(IChangeProxyTarget)}; } NestedClassEmitter nested = new NestedClassEmitter(emitter, "Invocation" + methodInfo.Name + "_" + nestedCounter.ToString(), typeof(AbstractInvocation), interfaces); // invocation only needs to mirror the generic parameters of the MethodInfo // targetType cannot be a generic type definition nested.CreateGenericParameters(methodInfo.GetGenericArguments()); // Create the invocation fields FieldReference targetRef = nested.CreateField("target", targetForInvocation); // Create constructor CreateIInvocationConstructor(targetForInvocation, nested, targetRef, version); if (allowChangeTarget) { ArgumentReference argument1 = new ArgumentReference(typeof(object)); MethodEmitter methodEmitter = nested.CreateMethod("ChangeInvocationTarget", MethodAttributes.Public | MethodAttributes.Virtual, typeof(void), argument1); methodEmitter.CodeBuilder.AddStatement( new AssignStatement(targetRef, new ConvertExpression(targetType, argument1.ToExpression()) ) ); methodEmitter.CodeBuilder.AddStatement(new ReturnStatement()); } // InvokeMethodOnTarget implementation if (callbackMethod != null) { ParameterInfo[] parameters = methodInfo.GetParameters(); CreateIInvocationInvokeOnTarget(emitter, nested, parameters, targetRef, callbackMethod); } else { CreateEmptyIInvocationInvokeOnTarget(nested); } nested.DefineCustomAttribute(new SerializableAttribute()); return nested; }