private void HandleMethods( TypeBuilder typeBuilder, Type interfaceType, FieldBuilder requesterField, FieldInfo classHeadersField, AllowAnyStatusCodeAttribute classAllowAnyStatusCodeAttribute, SerializationMethodsAttribute classSerializationMethodsAttribute, PropertyGrouping properties, out MethodInfoGrouping methodInfoGrouping) { int i = 0; methodInfoGrouping = new MethodInfoGrouping(); foreach (var methodInfo in InterfaceAndChildren(interfaceType, x => x.GetTypeInfo().GetMethods())) { // Exclude property getter / setters, etc if (methodInfo.IsSpecialName) { continue; } var parameters = methodInfo.GetParameters(); var parameterGrouping = new ParameterGrouping(parameters, methodInfo.Name); var methodBuilder = typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, methodInfo.ReturnType, parameters.Select(x => x.ParameterType).ToArray()); var methodIlGenerator = methodBuilder.GetILGenerator(); if (methodInfo == disposeMethod) { this.AddDisposeMethod(methodIlGenerator, requesterField); } else { var requestAttribute = methodInfo.GetCustomAttribute <RequestAttribute>(); if (requestAttribute == null) { throw new ImplementationCreationException(String.Format("Method {0} does not have a suitable [Get] / [Post] / etc attribute on it", methodInfo.Name)); } var allowAnyStatusCodeAttribute = methodInfo.GetCustomAttribute <AllowAnyStatusCodeAttribute>(); var methodSerializationMethodsAttribute = methodInfo.GetCustomAttribute <SerializationMethodsAttribute>(); var serializationMethods = new ResolvedSerializationMethods(classSerializationMethodsAttribute, methodSerializationMethodsAttribute); this.ValidatePathParams(requestAttribute.Path, parameterGrouping.PathParameters.Select(x => x.Attribute.Name ?? x.Parameter.Name).ToList(), properties.Path.Select(x => x.Attribute.Name).ToList(), methodInfo.Name); var methodInfoFieldBuilder = typeBuilder.DefineField("methodInfo<>_" + i, typeof(MethodInfo), FieldAttributes.Private | FieldAttributes.Static); methodInfoGrouping.Fields.Add(new MethodInfoFieldReference(methodInfo, methodInfoFieldBuilder)); this.AddRequestInfoCreation(methodIlGenerator, requesterField, requestAttribute, methodInfoFieldBuilder); this.AddCancellationTokenIfNeeded(methodIlGenerator, parameterGrouping.CancellationToken); this.AddClassHeadersIfNeeded(methodIlGenerator, classHeadersField); this.AddPropertyHeaders(methodIlGenerator, properties.Headers); this.AddPathProperties(methodIlGenerator, properties.Path); this.AddMethodHeaders(methodIlGenerator, methodInfo); this.AddAllowAnyStatusCodeIfNecessary(methodIlGenerator, allowAnyStatusCodeAttribute ?? classAllowAnyStatusCodeAttribute); this.AddParameters(methodIlGenerator, parameterGrouping, methodInfo.Name, serializationMethods); this.AddRequestMethodInvocation(methodIlGenerator, methodInfo); // Finally, return methodIlGenerator.Emit(OpCodes.Ret); typeBuilder.DefineMethodOverride(methodBuilder, methodInfo); } i++; } }
private void AddStaticCtor(TypeBuilder typeBuilder, HeaderAttribute[] classHeaders, FieldBuilder classHeadersField, MethodInfoGrouping methodInfoGrouping) { // static Name() // { // classHeaders = new List<KeyValuePair<string>>(n); // classHeaders.Add(new KeyValuePair<string, string>("name", "value")); // ... // methodInfoBackingField = new Lazy<MethodInfo>(methodInfoMethod); // ... // } var staticCtorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Static, CallingConventions.Standard, new Type[0]); var staticCtorIlGenerator = staticCtorBuilder.GetILGenerator(); if (classHeadersField != null) { // Load the list size onto the stack // Stack: [list size] staticCtorIlGenerator.Emit(OpCodes.Ldc_I4, classHeaders.Length); // Ctor the list // Stack: [list] staticCtorIlGenerator.Emit(OpCodes.Newobj, listOfKvpOfStringNCtor); // Load each class header into the list foreach (var classHeader in classHeaders) { staticCtorIlGenerator.Emit(OpCodes.Dup); staticCtorIlGenerator.Emit(OpCodes.Ldstr, classHeader.Name); staticCtorIlGenerator.Emit(OpCodes.Ldstr, classHeader.Value); // This value can never be null - we assert that earlier staticCtorIlGenerator.Emit(OpCodes.Newobj, kvpOfStringCtor); staticCtorIlGenerator.Emit(OpCodes.Callvirt, listOfKvpOfStringAdd); } // Finally, store the list in its static field staticCtorIlGenerator.Emit(OpCodes.Stsfld, classHeadersField); } foreach (var field in methodInfoGrouping.Fields) { staticCtorIlGenerator.Emit(OpCodes.Ldtoken, field.MethodInfo); if (field.MethodInfo.DeclaringType.GetTypeInfo().IsGenericType) { staticCtorIlGenerator.Emit(OpCodes.Ldtoken, field.MethodInfo.DeclaringType); staticCtorIlGenerator.Emit(OpCodes.Call, getMethodFromHandleWithDeclaringTypeMethod); } else { staticCtorIlGenerator.Emit(OpCodes.Call, getMethodFromHandleMethod); } staticCtorIlGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); staticCtorIlGenerator.Emit(OpCodes.Stsfld, field.BackingField); } staticCtorIlGenerator.Emit(OpCodes.Ret); }