/// <summary> /// Returns the iterator for <see cref="WorkflowBase.GetEnumerator()" />. /// </summary> /// <param name="obj">The underlying object.</param> /// <param name="contractName">The name of the contract.</param> /// <returns>The iterator.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="obj" /> is <see langword="null" />. /// </exception> protected IEnumerable <WorkflowFunc> GetFunctionIterator(object obj, IEnumerable <char> contractName) { if (obj == null) { throw new ArgumentNullException("obj"); } string contract = WorkflowAttributeBase.ParseContractName(contractName); Type type = obj.GetType(); IEnumerable <MethodInfo> allMethods = GetMethodsByType(type); List <Exception> occuredErrors = new List <Exception>(); // find start method MethodInfo currentMethod = null; { IEnumerable <MethodInfo> methodsWithAttribs = CollectionHelper.Where(allMethods, delegate(MethodInfo method) { // search for 'ReceiveNotificationFromAttribute' object[] attribs = method.GetCustomAttributes(typeof(global::MarcelJoachimKloubert.CLRToolbox.Execution.Workflows.WorkflowStartAttribute), true); // strong typed sequence IEnumerable <WorkflowStartAttribute> wfStartAttribs = CollectionHelper.OfType <WorkflowStartAttribute>(attribs); // filter by contract name IEnumerable <WorkflowStartAttribute> wfStartAttribForMethod = CollectionHelper.Where(wfStartAttribs, delegate(WorkflowStartAttribute a) { return(a.Contract == contract); }); return(CollectionHelper.Any(wfStartAttribForMethod)); }); currentMethod = CollectionHelper.SingleOrDefault(methodsWithAttribs); } IDictionary <string, object> execVars = this.CreateVarStorage(); bool hasBeenCanceled = false; long index = -1; IReadOnlyDictionary <string, object> previousVars = null; object result = null; object syncRoot = new object(); bool throwErrors = true; while ((hasBeenCanceled == false) && (currentMethod != null)) { yield return(delegate(object[] args) { SimpleWorkflowExecutionContext ctx = new SimpleWorkflowExecutionContext(); ctx.Cancel = false; ctx.ContinueOnError = false; ctx.ExecutionArguments = new TMReadOnlyList <object>(args ?? new object[] { null }); ctx.ExecutionVars = execVars; ctx.HasBeenCanceled = hasBeenCanceled; ctx.Index = ++index; ctx.NextVars = this.CreateVarStorage(); ctx.PreviousVars = previousVars; ctx.Result = result; ctx.SyncRoot = syncRoot; ctx.ThrowErrors = throwErrors; ctx.Workflow = this; ctx.WorkflowVars = this.Vars; // first try to find method for next step MethodInfo nextMethod = null; { // search for 'NextWorkflowStepAttribute' object[] attribs = currentMethod.GetCustomAttributes(typeof(global::MarcelJoachimKloubert.CLRToolbox.Execution.Workflows.NextWorkflowStepAttribute), true); // strong typed sequence IEnumerable <NextWorkflowStepAttribute> nextStepAttribs = CollectionHelper.OfType <NextWorkflowStepAttribute>(attribs); // filter by contract name NextWorkflowStepAttribute nextStep = CollectionHelper.SingleOrDefault(nextStepAttribs, delegate(NextWorkflowStepAttribute a) { return a.Contract == contract; }); if (nextStep != null) { IEnumerable <MethodInfo> nextMethods = CollectionHelper.Where(allMethods, delegate(MethodInfo m) { return m.Name == nextStep.Member; }); // first: try find with parameter nextMethod = CollectionHelper.SingleOrDefault(nextMethods, delegate(MethodInfo m) { return m.GetParameters().Length > 0; }); if (nextMethod == null) { // first: now find WITHOUT parameter nextMethod = CollectionHelper.Single(nextMethods, delegate(MethodInfo m) { return m.GetParameters().Length < 1; }); } } } // execution InvokeWorkflowMethod(obj, currentMethod, ctx, occuredErrors); WorkflowActionNoState nextAction = ctx.Next; if (nextAction == null) { currentMethod = nextMethod; } else { obj = nextAction.Target; currentMethod = nextAction.Method; type = currentMethod.ReflectedType; allMethods = GetMethodsByType(type); } previousVars = new TMReadOnlyDictionary <string, object>(ctx.NextVars); throwErrors = ctx.ThrowErrors; if (ctx.Cancel) { hasBeenCanceled = true; ctx.HasBeenCanceled = hasBeenCanceled; } return ctx; }); } if (throwErrors && (occuredErrors.Count > 0)) { throw new AggregateException(occuredErrors); } }