private PropertyGrouping HandleProperties(TypeBuilder typeBuilder, Type interfaceType)
        {
            var grouping = new PropertyGrouping(InterfaceAndChildren(interfaceType, x => x.GetTypeInfo().GetProperties()));
            MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.SpecialName;

            foreach (var property in grouping.AllProperties)
            {
                var propertyBuilder = typeBuilder.DefineProperty(property.PropertyInfo.Name, PropertyAttributes.None, property.PropertyInfo.PropertyType, null);
                var getter          = typeBuilder.DefineMethod(property.PropertyInfo.GetMethod.Name, attributes, property.PropertyInfo.PropertyType, new Type[0]);
                var setter          = typeBuilder.DefineMethod(property.PropertyInfo.SetMethod.Name, attributes, null, new Type[] { property.PropertyInfo.PropertyType });
                var backingField    = typeBuilder.DefineField("bk_" + property.PropertyInfo.Name, property.PropertyInfo.PropertyType, FieldAttributes.Private);

                var getterIlGenerator = getter.GetILGenerator();
                getterIlGenerator.Emit(OpCodes.Ldarg_0);
                getterIlGenerator.Emit(OpCodes.Ldfld, backingField);
                getterIlGenerator.Emit(OpCodes.Ret);
                propertyBuilder.SetGetMethod(getter);

                var setterIlGenerator = setter.GetILGenerator();
                setterIlGenerator.Emit(OpCodes.Ldarg_0);
                setterIlGenerator.Emit(OpCodes.Ldarg_1);
                setterIlGenerator.Emit(OpCodes.Stfld, backingField);
                setterIlGenerator.Emit(OpCodes.Ret);
                propertyBuilder.SetSetMethod(setter);

                property.BackingField = backingField;
            }

            return(grouping);
        }
        private void HandleMethods(
            TypeBuilder typeBuilder,
            Type interfaceType,
            FieldBuilder requesterField,
            FieldInfo classHeadersField,
            AllowAnyStatusCodeAttribute classAllowAnyStatusCodeAttribute,
            SerializationMethodsAttribute classSerializationMethodsAttribute,
            PropertyGrouping properties)
        {
            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);

                    this.AddRequestInfoCreation(methodIlGenerator, requesterField, requestAttribute);
                    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);
                }
            }
        }