/// <summary>
        /// Explicitly registers an action stage given a key and a corresponding type
        /// </summary>
        /// <param name="key">The action key (e.g. "$filter" for the $filter stage)</param>
        /// <param name="type">The type that implements the stage</param>
        public static void RegisterActionStage(string key, Type type)
        {
            if (type.IsSubclassOf(typeof(PipelineStage)) == false)
            {
                throw new InvalidArgDefinitionException("The type '" + type.FullName + "' does not implement " + typeof(PipelineStage).FullName);
            }

            key = new ArgPipelineActionStage(key).Key;
            AssertKeyNotAlreadyRegistered(key);
            registeredActionStageTypes.Add(key, type);
        }
        /// <summary>
        /// Explicitly registers an action stage given a key and a corresponding type
        /// </summary>
        /// <param name="key">The action key (e.g. "$filter" for the $filter stage)</param>
        /// <param name="type">The type that implements the stage</param>
        public static void RegisterActionStage(string key, Type type)
        {
            if (type.IsSubclassOf(typeof(PipelineStage)) == false)
            {
                throw new InvalidArgDefinitionException("The type '" + type.FullName + "' does not implement " + typeof(PipelineStage).FullName);
            }

            key = new ArgPipelineActionStage(key).Key;
            AssertKeyNotAlreadyRegistered(key);
            registeredActionStageTypes.Add(key, type);
        }
        internal PipelineStage CreateNextStage(ArgHook.HookContext context, string[] commandLine, ICommandLineArgumentsDefinitionFactory factory)
        {
            PipelineStage     next;
            CommandLineAction inProcAction;

            if (Stages.Count == 0)
            {
                next = new RootPipelineStage(commandLine);
            }
            else if (commandLine[0].StartsWith(ArgPipeline.PipelineStageActionIndicator) && ArgPipelineActionStage.TryCreateActionStage(commandLine, out next))
            {
                // do nothing, next is populated
            }
            else if (TryParseStageAction(context.Definition, commandLine[0], out inProcAction))
            {
                next = new InProcessPipelineStage(context.Definition, commandLine);
            }
            else if (ExternalPipelineProvider.TryLoadOutputStage(commandLine, out next) == false)
            {
                throw new UnexpectedArgException("The pipeline action '" + string.Join(" ", commandLine) + "' is not valid.  If you want to support piping between processes, learn how to here (TODO URL)");
            }

            next.CommandLineDefinitionFactory = factory;

            this.AddStage(next);
            return(next);
        }