private void EmitUsingDefinitionValue(ILGenerator ilGenerator, FluentActionDefinition fluentActionDefinition, FluentActionUsingDefinition usingDefinition, Dictionary <int, int> methodParameterIndices, StateMachineState state, int stateIndex, int handlerInStateIndex)
        {
            if (usingDefinition.IsMethodParameter)
            {
                var usingDefinitionHash  = usingDefinition.GetHashCode();
                var methodParameterIndex = methodParameterIndices[usingDefinitionHash];

                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldfld, MethodParameterFields[methodParameterIndex - 1]);
            }
            else if (usingDefinition.IsControllerProperty)
            {
                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldfld, ParentField);
                ilGenerator.Emit(OpCodes.Callvirt,
                                 typeof(Controller).GetProperty(usingDefinition.ControllerPropertyName).GetGetMethod());
            }
            else if (usingDefinition is FluentActionUsingPropertyDefinition)
            {
                var propertyName = ((FluentActionUsingPropertyDefinition)usingDefinition).PropertyName;
                var parentType   = fluentActionDefinition.ParentType ?? typeof(Controller);
                var property     = parentType.GetProperty(propertyName);
                if (property == null)
                {
                    throw new Exception($"Could not find property {propertyName} on type {parentType.FullName}.");
                }

                var propertyGetMethod = property.GetGetMethod();
                if (propertyGetMethod == null)
                {
                    throw new Exception($"Missing public get method on property {propertyName} on type {parentType.FullName}.");
                }

                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldfld, ParentField);
                ilGenerator.Emit(OpCodes.Callvirt, propertyGetMethod);
            }
            else if (usingDefinition is FluentActionUsingParentDefinition)
            {
                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldfld, ParentField);
            }
            else if (usingDefinition is FluentActionUsingResultDefinition)
            {
                FieldBuilder resultFieldToLoad;
                if (handlerInStateIndex > 0)
                {
                    resultFieldToLoad = state.Handlers[handlerInStateIndex - 1].ResultField;
                }
                else
                {
                    resultFieldToLoad = States[stateIndex - 1].ResultField;
                }

                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldfld, resultFieldToLoad);

                if (resultFieldToLoad.FieldType.IsValueType)
                {
                    ilGenerator.Emit(OpCodes.Box, resultFieldToLoad.FieldType);
                }
            }
            else
            {
                throw new Exception($"Got unknown using definition: {usingDefinition.GetType()}");
            }
        }
        private void EmitUsingDefinitionValue(
            ILGenerator ilGenerator,
            FluentActionUsingDefinition usingDefinition,
            Dictionary <int, int> methodParameterIndices,
            LocalBuilder localVariableForPreviousReturnValue)
        {
            var ilHandle = new IlHandle {
                Generator = ilGenerator
            };

            var usingDefinitionHash  = usingDefinition.GetHashCode();
            var methodParameterIndex = methodParameterIndices.ContainsKey(usingDefinitionHash) ?
                                       methodParameterIndices[usingDefinitionHash] : -1;

            if (usingDefinition.IsMethodParameter)
            {
                ilHandle.Generator.Emit(OpCodes.Ldarg, methodParameterIndex);
            }
            else if (usingDefinition.IsControllerProperty)
            {
                ilHandle.Generator.Emit(OpCodes.Ldarg_0);
                ilHandle.Generator.Emit(OpCodes.Callvirt,
                                        typeof(Controller).GetProperty(usingDefinition.ControllerPropertyName).GetGetMethod());
            }
            else if (usingDefinition is FluentActionUsingPropertyDefinition)
            {
                var propertyName = ((FluentActionUsingPropertyDefinition)usingDefinition).PropertyName;
                var parentType   = FluentActionDefinition.ParentType ?? typeof(Controller);
                var property     = parentType.GetProperty(propertyName);
                if (property == null)
                {
                    throw new Exception($"Could not find property {propertyName} on type {parentType.FullName}.");
                }

                var propertyGetMethod = property.GetGetMethod();
                if (propertyGetMethod == null)
                {
                    throw new Exception($"Missing public get method on property {propertyName} on type {parentType.FullName}.");
                }

                ilHandle.Generator.Emit(OpCodes.Ldarg_0);
                ilHandle.Generator.Emit(OpCodes.Callvirt, propertyGetMethod);
            }
            else if (usingDefinition is FluentActionUsingParentDefinition)
            {
                ilHandle.Generator.Emit(OpCodes.Ldarg_0);
            }
            else if (usingDefinition is FluentActionUsingResultDefinition)
            {
                if (localVariableForPreviousReturnValue == null)
                {
                    throw new Exception("Cannot use previous result from handler as no previous result exists.");
                }

                ilHandle.Generator.Emit(OpCodes.Ldloc, localVariableForPreviousReturnValue);
                if (localVariableForPreviousReturnValue.LocalType.IsValueType)
                {
                    ilHandle.Generator.Emit(OpCodes.Box, localVariableForPreviousReturnValue.LocalType);
                }
            }
            else
            {
                throw new Exception($"Got unknown using definition: {usingDefinition.GetType()}");
            }
        }