public static object HandleInvocation( IProxy target, InvocationFactory invocationFactory, Type[] genericArguments, object[] parameterValues, object returnValue) { var invocation = invocationFactory.CreateInvocation(target, genericArguments, parameterValues, returnValue); var invocationInterceptor = target.InvocationInterceptor; invocationInterceptor.OnInvocation(invocation); return(invocation.returnValue); }
MethodInfo[] GetBaseMethods(Type interfaceType) { if (interfaceType.IsDelegateType()) { return new[] { interfaceType.GetMethod(DelegateInvokeMethodName) } } ; var interfaceMethods = GetInterfaceMethods(interfaceType); var objectMethods = GetVirtualMethodsDeclaredInObject(); return(interfaceMethods.Concat(objectMethods).ToArray()); } ConstructorInfo GetBaseConstructor(Type baseType) { return(baseType.GetConstructor( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object), typeof(IInvocationInterceptor) }, null)); } MethodInfo[] GetInterfaceMethods(Type interfaceType) { var interfaceMethods = new List <MethodInfo>(interfaceType.GetMethods()); foreach (Type subInterfaceType in interfaceType.GetInterfaces()) { interfaceMethods.AddRange(GetInterfaceMethods(subInterfaceType)); } return(interfaceMethods.Distinct().ToArray()); } MethodInfo[] GetVirtualMethodsDeclaredInObject() { return(typeof(object).GetMethods().Where(method => method.IsVirtual).ToArray()); } FieldInfo[] ImplementClassConstructor(TypeBuilder typeBuilder, MethodInfo[] baseMethods) { var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Static, CallingConventions.Standard, null); var ilGenerator = constructorBuilder.GetILGenerator(); var invocationFactoryFields = new FieldInfo[baseMethods.Length]; for (int i = 0; i < baseMethods.Length; i++) { var baseMethod = baseMethods[i]; var declaringType = baseMethod.DeclaringType; var invocationFactoryField = ImplementInvocationFactoriesField(typeBuilder, i); if (baseMethod.IsGenericMethodDefinition) { string methodTextRepresentation = InvocationFactory.GetTextRepresentationForMethod(baseMethod); ilGenerator.Emit(OpCodes.Ldtoken, declaringType); ilGenerator.Emit(OpCodes.Call, Methods.GetTypeFromHandle); ilGenerator.Emit(OpCodes.Ldstr, methodTextRepresentation); ilGenerator.Emit(OpCodes.Call, Methods.GetInvocationFactoryForMethodTextRepresentation); ilGenerator.Emit(OpCodes.Stsfld, invocationFactoryField); } else { ilGenerator.Emit(OpCodes.Ldtoken, baseMethod); ilGenerator.Emit(OpCodes.Ldtoken, declaringType); ilGenerator.Emit(OpCodes.Call, Methods.GetMethodFromHandle); ilGenerator.Emit(OpCodes.Call, Methods.GetInvocationFactoryForMethod); ilGenerator.Emit(OpCodes.Stsfld, invocationFactoryField); } invocationFactoryFields[i] = invocationFactoryField; } ilGenerator.Emit(OpCodes.Ret); return(invocationFactoryFields); } FieldInfo ImplementInvocationFactoriesField(TypeBuilder typeBuilder, int fieldIndex) { string fieldName = string.Format(InvocationFactoryFieldNameFormat, fieldIndex); var fieldType = typeof(InvocationFactory); var fieldAttributes = FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly; return(typeBuilder.DefineField(fieldName, fieldType, fieldAttributes)); } void ImplementConstructor(TypeBuilder typeBuilder, ConstructorInfo baseConstructor) { var methodAttributes = MethodAttributes.Public; var callingConvention = baseConstructor.CallingConvention; var parameterTypes = (from parameter in baseConstructor.GetParameters() select parameter.ParameterType).ToList(); var constructorBuilder = typeBuilder.DefineConstructor(methodAttributes, callingConvention, parameterTypes.ToArray()); var ilGenerator = constructorBuilder.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldarg_0); for (int i = 0; i < parameterTypes.Count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i + 1); } ilGenerator.Emit(OpCodes.Call, baseConstructor); ilGenerator.Emit(OpCodes.Ret); } void ImplementMethods(TypeBuilder typeBuilder, MethodInfo[] baseMethods, FieldInfo[] invocationFactoryFields) { for (int i = 0; i < baseMethods.Length; i++) { var baseMethod = baseMethods[i]; var invocationFactoryField = invocationFactoryFields[i]; ImplementMethod(typeBuilder, baseMethod, invocationFactoryField); } } void ImplementMethod(TypeBuilder typeBuilder, MethodInfo baseMethod, FieldInfo invocationFactoryField) { string methodName; var methodAttributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot; bool isMethodOverride; if (baseMethod.DeclaringType.IsDelegateType()) { methodName = DelegateInvokeMethodName; methodAttributes |= MethodAttributes.Public; isMethodOverride = false; } else { methodName = GetProxyMethodName(baseMethod); methodAttributes |= MethodAttributes.Private; isMethodOverride = true; } var methodBuilder = typeBuilder.DefineMethod(methodName, methodAttributes); DefineMethodSignature(methodBuilder, baseMethod); EmitMethodBody(methodBuilder, baseMethod, invocationFactoryField); if (isMethodOverride) { typeBuilder.DefineMethodOverride(methodBuilder, baseMethod); } } void DefineMethodSignature(MethodBuilder methodBuilder, MethodInfo baseMethod) { if (baseMethod.IsGenericMethodDefinition) { var baseGenericArguments = baseMethod.GetGenericArguments(); var genericParameterBuilders = methodBuilder.DefineGenericParameters(baseGenericArguments.Select(type => type.Name).ToArray()); for (int i = 0; i < genericParameterBuilders.Length; i++) { var baseGenericArgument = baseGenericArguments[i]; var genericParameterBuilder = genericParameterBuilders[i]; foreach (var baseTypeConstraint in baseGenericArgument.GetGenericParameterConstraints()) { if (baseTypeConstraint.IsInterface) { genericParameterBuilder.SetInterfaceConstraints(baseTypeConstraint); } else { genericParameterBuilder.SetBaseTypeConstraint(baseTypeConstraint); } } } } var baseMethodParameters = baseMethod.GetParameters(); methodBuilder.SetParameters(baseMethodParameters.Select(parameter => parameter.ParameterType).ToArray()); methodBuilder.SetReturnType(baseMethod.ReturnType); for (int i = 0; i < baseMethodParameters.Length; i++) { var parameter = baseMethodParameters[i]; methodBuilder.DefineParameter(i, parameter.Attributes, parameter.Name); } } void EmitMethodBody(MethodBuilder methodBuilder, MethodInfo baseMethod, FieldInfo invocationFactoryField) { var ilGenerator = methodBuilder.GetILGenerator(); ilGenerator.DeclareLocal(typeof(InvocationFactory)); ilGenerator.DeclareLocal(typeof(Type[])); ilGenerator.DeclareLocal(typeof(object[])); if (baseMethod.ReturnType != typeof(void)) { ilGenerator.DeclareLocal(baseMethod.ReturnType); } EmitLoadInvocationFactoriesField(ilGenerator, invocationFactoryField); EmitBuildGenericArgumentsArray(ilGenerator, baseMethod); EmitBuildParameterValuesArray(ilGenerator, baseMethod); EmitCallHandleInvocation(ilGenerator, baseMethod); EmitReflectOutgoingParameterValues(ilGenerator, baseMethod); ilGenerator.Emit(OpCodes.Ret); } void EmitLoadInvocationFactoriesField(ILGenerator ilGenerator, FieldInfo invocationFactoriesField) { ilGenerator.Emit(OpCodes.Ldsfld, invocationFactoriesField); ilGenerator.Emit(OpCodes.Stloc_0); } void EmitBuildGenericArgumentsArray(ILGenerator ilGenerator, MethodInfo baseMethod) { if (!baseMethod.IsGenericMethodDefinition) { ilGenerator.Emit(OpCodes.Ldnull); ilGenerator.Emit(OpCodes.Stloc_1); return; } var genericMethodArguments = baseMethod.GetGenericArguments(); ilGenerator.Emit(OpCodes.Ldc_I4, genericMethodArguments.Length); ilGenerator.Emit(OpCodes.Newarr, typeof(Type)); ilGenerator.Emit(OpCodes.Stloc_1); for (int i = 0; i < genericMethodArguments.Length; i++) { ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Ldc_I4, i); ilGenerator.Emit(OpCodes.Ldtoken, genericMethodArguments[i]); ilGenerator.Emit(OpCodes.Call, Methods.GetTypeFromHandle); ilGenerator.Emit(OpCodes.Stelem_Ref); } } void EmitBuildParameterValuesArray(ILGenerator ilGenerator, MethodInfo baseMethod) { var baseMethodParameters = baseMethod.GetParameters(); ilGenerator.Emit(OpCodes.Ldc_I4, baseMethodParameters.Length); ilGenerator.Emit(OpCodes.Newarr, typeof(object)); ilGenerator.Emit(OpCodes.Stloc_2); for (int i = 0; i < baseMethodParameters.Length; i++) { var parameter = baseMethodParameters[i]; var parameterType = parameter.ParameterType; ilGenerator.Emit(OpCodes.Ldloc_2); ilGenerator.Emit(OpCodes.Ldc_I4, i); ilGenerator.Emit(OpCodes.Ldarg, i + 1); if (parameterType.IsByRef) { parameterType = parameterType.GetElementType(); ilGenerator.EmitLoadIndirect(parameterType); } EmitBoxValue(ilGenerator, parameterType); ilGenerator.Emit(OpCodes.Stelem_Ref); } } void EmitLoadDefaultReturnValue(ILGenerator ilGenerator, Type returnType) { ilGenerator.Emit(OpCodes.Ldloca_S, 3); ilGenerator.Emit(OpCodes.Initobj, returnType); ilGenerator.Emit(OpCodes.Ldloc_3); EmitBoxValue(ilGenerator, returnType); } void EmitBoxValue(ILGenerator ilGenerator, Type parameterType) { if (parameterType.IsValueType || parameterType.IsGenericParameter) { ilGenerator.Emit(OpCodes.Box, parameterType); } } void EmitCallHandleInvocation(ILGenerator ilGenerator, MethodInfo baseMethod) { ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Ldloc_2); if (baseMethod.ReturnType == typeof(void)) { ilGenerator.Emit(OpCodes.Ldnull); ilGenerator.Emit(OpCodes.Call, Methods.HandleInvocation); ilGenerator.Emit(OpCodes.Pop); } else { EmitLoadDefaultReturnValue(ilGenerator, baseMethod.ReturnType); ilGenerator.Emit(OpCodes.Call, Methods.HandleInvocation); ilGenerator.Emit(OpCodes.Unbox_Any, baseMethod.ReturnType); } } void EmitReflectOutgoingParameterValues(ILGenerator ilGenerator, MethodInfo baseMethod) { var baseMethodParameters = baseMethod.GetParameters(); for (int i = 0; i < baseMethodParameters.Length; i++) { var parameter = baseMethodParameters[i]; var parameterType = parameter.ParameterType; if (!parameterType.IsByRef) { continue; } parameterType = parameterType.GetElementType(); ilGenerator.Emit(OpCodes.Ldarg, i + 1); ilGenerator.Emit(OpCodes.Ldloc_2); ilGenerator.Emit(OpCodes.Ldc_I4, i); ilGenerator.Emit(OpCodes.Ldelem_Ref); ilGenerator.Emit(OpCodes.Unbox_Any, parameterType); ilGenerator.EmitStoreIndirect(parameterType); } }