/// <summary> /// Generates the constructor for the nested class that extends /// <see cref="AbstractInvocation"/> /// </summary> /// <param name="targetFieldType"></param> /// <param name="nested"></param> /// <param name="targetField"></param> /// <param name="version"></param> protected void CreateIInvocationConstructor( Type targetFieldType, NestedClassEmitter nested, FieldReference targetField, ConstructorVersion version) { ArgumentReference cArg0 = new ArgumentReference(targetFieldType); ArgumentReference cArg1 = new ArgumentReference(typeof(IInterceptor[])); ArgumentReference cArg2 = new ArgumentReference(typeof(Type)); ArgumentReference cArg3 = new ArgumentReference(typeof(MethodInfo)); ArgumentReference cArg4 = null; ArgumentReference cArg6 = new ArgumentReference(typeof(object)); if (version == ConstructorVersion.WithTargetMethod) { cArg4 = new ArgumentReference(typeof(MethodInfo)); } ArgumentReference cArg5 = new ArgumentReference(typeof(object[])); ConstructorEmitter constructor; if (cArg4 == null) { constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg5, cArg6); } else { constructor = nested.CreateConstructor(cArg0, cArg1, cArg2, cArg3, cArg4, cArg5, cArg6); } constructor.CodeBuilder.AddStatement(new AssignStatement(targetField, cArg0.ToExpression())); if (cArg4 == null) { constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithoutTargetMethod, cArg0, cArg6, cArg1, cArg2, cArg3, cArg5); } else { constructor.CodeBuilder.InvokeBaseConstructor(Constants.AbstractInvocationConstructorWithTargetMethod, cArg0, cArg6, cArg1, cArg2, cArg3, cArg4, cArg5); } constructor.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; }
/// <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> /// <returns></returns> protected NestedClassEmitter BuildInvocationNestedType( ClassEmitter emitter, Type targetType, Type targetForInvocation, MethodInfo methodInfo, MethodInfo callbackMethod, ConstructorVersion version) { CheckNotGenericTypeDefinition(targetType, "targetType"); CheckNotGenericTypeDefinition(targetForInvocation, "targetForInvocation"); return BuildInvocationNestedType(emitter, targetType, targetForInvocation, methodInfo, callbackMethod, version, false); }
protected MethodEmitter ImplementProxiedMethod( Type targetType, MethodEmitter methodEmitter, MethodInfo method, ClassEmitter emitter, NestedClassEmitter invocationImpl, FieldReference interceptorsField, Reference targetRef, ConstructorVersion version, MethodInfo methodOnTarget) { CheckNotGenericTypeDefinition(targetType, "targetType"); methodEmitter.CopyParametersAndReturnTypeFrom(method, emitter); TypeReference[] dereferencedArguments = IndirectReference.WrapIfByRef(methodEmitter.Arguments); Type iinvocation = invocationImpl.TypeBuilder; Trace.Assert(method.IsGenericMethod == iinvocation.IsGenericTypeDefinition); bool isGenericInvocationClass = false; Type[] genericMethodArgs = new Type[0]; if (method.IsGenericMethod) { // bind generic method arguments to invocation's type arguments genericMethodArgs = methodEmitter.MethodBuilder.GetGenericArguments(); iinvocation = iinvocation.MakeGenericType(genericMethodArgs); isGenericInvocationClass = true; } LocalReference invocationImplLocal = methodEmitter.CodeBuilder.DeclareLocal(iinvocation); // TODO: Initialize iinvocation instance // with ordinary arguments and in and out arguments Expression interceptors; // if (useSelector) { // TODO: Generate code that checks the return of selector // if no interceptors is returned, should we invoke the base.Method directly? } // else { interceptors = interceptorsField.ToExpression(); } Expression typeTokenFieldExp = typeTokenField.ToExpression(); Expression methodInfoTokenExp; if (method2TokenField.ContainsKey(method)) // Token is in the cache { methodInfoTokenExp = ((FieldReference) method2TokenField[method]).ToExpression(); } else { // Not in the cache: generic method methodInfoTokenExp = new MethodTokenExpression(method.MakeGenericMethod(genericMethodArgs)); } ConstructorInfo constructor = invocationImpl.Constructors[0].ConstructorBuilder; if (isGenericInvocationClass) { constructor = TypeBuilder.GetConstructor(iinvocation, invocationImpl.Constructors[0].ConstructorBuilder); } NewInstanceExpression newInvocImpl; if (version == ConstructorVersion.WithTargetMethod) { Expression methodOnTargetTokenExp; if (method2TokenField.ContainsKey(methodOnTarget)) // Token is in the cache { methodOnTargetTokenExp = ((FieldReference) method2TokenField[methodOnTarget]).ToExpression(); } else { // Not in the cache: generic method methodOnTargetTokenExp = new MethodTokenExpression(methodOnTarget.MakeGenericMethod(genericMethodArgs)); } newInvocImpl = new NewInstanceExpression(constructor, targetRef.ToExpression(), interceptors, typeTokenFieldExp, methodOnTargetTokenExp, methodInfoTokenExp, new ReferencesToObjectArrayExpression(dereferencedArguments), SelfReference.Self.ToExpression()); } else { newInvocImpl = new NewInstanceExpression(constructor, targetRef.ToExpression(), interceptors, typeTokenFieldExp, methodInfoTokenExp, new ReferencesToObjectArrayExpression(dereferencedArguments), SelfReference.Self.ToExpression()); } methodEmitter.CodeBuilder.AddStatement(new AssignStatement(invocationImplLocal, newInvocImpl)); if (method.ContainsGenericParameters) { EmitLoadGenricMethodArguments(methodEmitter, method.MakeGenericMethod(genericMethodArgs), invocationImplLocal); } methodEmitter.CodeBuilder.AddStatement( new ExpressionStatement(new MethodInvocationExpression(invocationImplLocal, Constants.AbstractInvocationProceed))); CopyOutAndRefParameters(dereferencedArguments, invocationImplLocal, method, methodEmitter); if (method.ReturnType != typeof(void)) { // Emit code to return with cast from ReturnValue MethodInvocationExpression getRetVal = new MethodInvocationExpression(invocationImplLocal, typeof(AbstractInvocation).GetMethod("get_ReturnValue")); methodEmitter.CodeBuilder.AddStatement( new ReturnStatement(new ConvertExpression(methodEmitter.ReturnType, getRetVal))); } else { methodEmitter.CodeBuilder.AddStatement(new ReturnStatement()); } return methodEmitter; }
protected MethodEmitter CreateProxiedMethod( Type targetType, MethodInfo method, ClassEmitter emitter, NestedClassEmitter invocationImpl, FieldReference interceptorsField, Reference targetRef, ConstructorVersion version, MethodInfo methodOnTarget) { CheckNotGenericTypeDefinition(targetType, "targetType"); MethodAttributes atts = ObtainMethodAttributes(method); MethodEmitter methodEmitter = emitter.CreateMethod(method.Name, atts); return ImplementProxiedMethod(targetType, methodEmitter, method, emitter, invocationImpl, interceptorsField, targetRef, version, methodOnTarget); }
protected MethodEmitter ImplementProxiedMethod( Type targetType, MethodEmitter methodEmitter, MethodInfo method, ClassEmitter emitter, NestedClassEmitter invocationImpl, FieldReference interceptorsField, Reference targetRef, ConstructorVersion version, MethodInfo methodOnTarget) { CheckNotGenericTypeDefinition(targetType, "targetType"); methodEmitter.CopyParametersAndReturnTypeFrom(method, emitter); TypeReference[] dereferencedArguments = IndirectReference.WrapIfByRef(methodEmitter.Arguments); Type iinvocation = invocationImpl.TypeBuilder; Trace.Assert(method.IsGenericMethod == iinvocation.IsGenericTypeDefinition); bool isGenericInvocationClass = false; Type[] genericMethodArgs = new Type[0]; if (method.IsGenericMethod) { // bind generic method arguments to invocation's type arguments genericMethodArgs = methodEmitter.MethodBuilder.GetGenericArguments(); iinvocation = iinvocation.MakeGenericType(genericMethodArgs); isGenericInvocationClass = true; } Expression typeTokenFieldExp = typeTokenField.ToExpression(); Expression methodInfoTokenExp; string tokenFieldName; if (method2TokenField.ContainsKey(method)) // Token is in the cache { FieldReference methodTokenField = method2TokenField[method]; tokenFieldName = methodTokenField.Reference.Name; methodInfoTokenExp = methodTokenField.ToExpression(); } else { // Not in the cache: generic method MethodInfo genericMethod = method.MakeGenericMethod(genericMethodArgs); // Need random suffix added to the name, so that we don't end up with duplicate field names for // methods with the same name, but different generic parameters tokenFieldName = string.Format("{0}_{1}_{2}", genericMethod.Name, genericMethodArgs.Length, Guid.NewGuid().ToString("N")); methodInfoTokenExp = new MethodTokenExpression(genericMethod); } LocalReference invocationImplLocal = methodEmitter.CodeBuilder.DeclareLocal(iinvocation); // TODO: Initialize iinvocation instance with ordinary arguments and in and out arguments Expression interceptors = interceptorsField.ToExpression(); // Create the field to store the selected interceptors for this method if an InterceptorSelector is specified FieldReference methodInterceptors = null; if (proxyGenerationOptions.Selector != null) { // If no interceptors are returned, should we invoke the base.Method directly? Looks like we should not. methodInterceptors = emitter.CreateField(string.Format("{0}_interceptors", tokenFieldName), typeof(IInterceptor[])); } ConstructorInfo constructor = invocationImpl.Constructors[0].ConstructorBuilder; if (isGenericInvocationClass) { constructor = TypeBuilder.GetConstructor(iinvocation, constructor); } NewInstanceExpression newInvocImpl; if (version == ConstructorVersion.WithTargetMethod) { Expression methodOnTargetTokenExp; if (method2TokenField.ContainsKey(methodOnTarget)) // Token is in the cache { methodOnTargetTokenExp = method2TokenField[methodOnTarget].ToExpression(); } else { // Not in the cache: generic method methodOnTargetTokenExp = new MethodTokenExpression(methodOnTarget.MakeGenericMethod(genericMethodArgs)); } if (methodInterceptors == null) { newInvocImpl = //actual contructor call new NewInstanceExpression(constructor, targetRef.ToExpression(), interceptors, typeTokenFieldExp, methodOnTargetTokenExp, methodInfoTokenExp, new ReferencesToObjectArrayExpression(dereferencedArguments), SelfReference.Self.ToExpression()); } else { MethodInvocationExpression methodInvocationExpression = new MethodInvocationExpression(proxyGenerationOptionsField, proxyGenerationOptions_Selector); methodInvocationExpression.VirtualCall = true; newInvocImpl = //actual contructor call new NewInstanceExpression(constructor, targetRef.ToExpression(), interceptors, typeTokenFieldExp, methodOnTargetTokenExp, methodInfoTokenExp, new ReferencesToObjectArrayExpression(dereferencedArguments), SelfReference.Self.ToExpression(), methodInvocationExpression, new AddressOfReferenceExpression(methodInterceptors)); } } else { if (methodInterceptors == null) { newInvocImpl = new NewInstanceExpression(constructor, targetRef.ToExpression(), interceptors, typeTokenFieldExp, methodInfoTokenExp, new ReferencesToObjectArrayExpression(dereferencedArguments), SelfReference.Self.ToExpression()); } else { MethodInvocationExpression methodInvocationExpression = new MethodInvocationExpression(proxyGenerationOptionsField, proxyGenerationOptions_Selector); methodInvocationExpression.VirtualCall = true; newInvocImpl = new NewInstanceExpression(constructor, targetRef.ToExpression(), interceptors, typeTokenFieldExp, methodInfoTokenExp, new ReferencesToObjectArrayExpression(dereferencedArguments), SelfReference.Self.ToExpression(), methodInvocationExpression, new AddressOfReferenceExpression(methodInterceptors)); } } methodEmitter.CodeBuilder.AddStatement(new AssignStatement(invocationImplLocal, newInvocImpl)); if (method.ContainsGenericParameters) { EmitLoadGenricMethodArguments(methodEmitter, method.MakeGenericMethod(genericMethodArgs), invocationImplLocal); } methodEmitter.CodeBuilder.AddStatement( new ExpressionStatement(new MethodInvocationExpression(invocationImplLocal, Constants.AbstractInvocationProceed))); CopyOutAndRefParameters(dereferencedArguments, invocationImplLocal, method, methodEmitter); if (method.ReturnType != typeof(void)) { // Emit code to return with cast from ReturnValue MethodInvocationExpression getRetVal = new MethodInvocationExpression(invocationImplLocal, typeof(AbstractInvocation).GetMethod("get_ReturnValue")); methodEmitter.CodeBuilder.AddStatement( new ReturnStatement(new ConvertExpression(methodEmitter.ReturnType, getRetVal))); } else { methodEmitter.CodeBuilder.AddStatement(new ReturnStatement()); } return methodEmitter; }