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 DefineStates(FluentActionDefinition fluentActionDefinition) { var handlersPerState = fluentActionDefinition.Handlers .Divide(handler => handler.Async) .Select(handlers => handlers.ToArray()) .ToArray(); States = new StateMachineState[handlersPerState.Length]; for (var stateIndex = 0; stateIndex < handlersPerState.Length; stateIndex++) { var handlersInState = handlersPerState[stateIndex]; var state = new StateMachineState { Handlers = new StateMachineStateHandler[handlersInState.Length] }; for (var handlerIndex = 0; handlerIndex < handlersInState.Length; handlerIndex++) { var handlerDefinition = handlersInState[handlerIndex]; state.Handlers[handlerIndex] = new StateMachineStateHandler { Definition = handlerDefinition }; if (handlerDefinition.Type == FluentActionHandlerType.Func) { state.Handlers[handlerIndex].DelegateField = Type.DefineField( $"State{stateIndex}Handler{handlerIndex}Delegate", BuilderHelper.GetDelegateType(handlerDefinition), FieldAttributes.Public); state.Handlers[handlerIndex].ResultField = Type.DefineField( $"State{stateIndex}Handler{handlerIndex}Result", handlerDefinition.ReturnType, FieldAttributes.Public); } else if (handlerDefinition.Type == FluentActionHandlerType.Action) { state.Handlers[handlerIndex].DelegateField = Type.DefineField( $"State{stateIndex}Handler{handlerIndex}Delegate", BuilderHelper.GetDelegateType(handlerDefinition), FieldAttributes.Public); } else if ( handlerDefinition.Type == FluentActionHandlerType.View || handlerDefinition.Type == FluentActionHandlerType.PartialView || handlerDefinition.Type == FluentActionHandlerType.ViewComponent) { state.Handlers[handlerIndex].ResultField = Type.DefineField( $"State{stateIndex}Handler{handlerIndex}Result", handlerDefinition.ReturnType, FieldAttributes.Public); } } var lastHandlerInState = handlersInState.Last(); if (lastHandlerInState.Type == FluentActionHandlerType.Func) { state.ResultType = lastHandlerInState.ReturnType; state.ResultField = Type.DefineField( $"State{stateIndex}ReturnType", state.ResultType, FieldAttributes.Public); state.TaskAwaiterType = typeof(TaskAwaiter <>) .MakeGenericType(lastHandlerInState.ReturnType); state.TaskAwaiterField = Type.DefineField( $"State{stateIndex}Awaiter", state.TaskAwaiterType, FieldAttributes.Public); state.WaitingField = Type.DefineField( $"State{stateIndex}WaitingFlag", typeof(bool), FieldAttributes.Public); } else if (lastHandlerInState.Type == FluentActionHandlerType.Action) { state.ResultType = lastHandlerInState.ReturnType; // state.ResultField is not used since an Action returns void state.TaskAwaiterType = typeof(TaskAwaiter); state.TaskAwaiterField = Type.DefineField( $"State{stateIndex}Awaiter", state.TaskAwaiterType, FieldAttributes.Public); state.WaitingField = Type.DefineField( $"State{stateIndex}WaitingFlag", typeof(bool), FieldAttributes.Public); } else if (lastHandlerInState.Type == FluentActionHandlerType.View || lastHandlerInState.Type == FluentActionHandlerType.PartialView || lastHandlerInState.Type == FluentActionHandlerType.ViewComponent) { state.ResultType = lastHandlerInState.ReturnType; state.ResultField = Type.DefineField( $"State{stateIndex}ReturnType", state.ResultType, FieldAttributes.Public); } States[stateIndex] = state; } }