/// <summary> /// Configures the specified pipeline stage to receive log messages, when the current stage has completed running /// its <see cref="ProcessMessage"/> method. The method must return <c>true</c> to call the following stage. /// The pipeline stage must use the same log configuration as the current stage and it must not be initialized, yet. /// </summary> /// <param name="stage">The pipeline stage that should follow the current stage.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="stage"/> is <c>null</c>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="stage"/> is already initialized or its configuration is not the same as the configuration of the current state. /// </exception> public void AddNextStage(ProcessingPipelineStage stage) { if (stage == null) { throw new ArgumentNullException(nameof(stage)); } if (stage.IsInitialized) { throw new ArgumentException("The stage to add must not be initialized.", nameof(stage)); } if (!ReferenceEquals(stage.Configuration, Configuration)) { throw new ArgumentException("The stage must use the same configuration as the current stage.", nameof(stage)); } lock (Sync) { var oldNextStages = mNextStages; var copy = new ProcessingPipelineStage[mNextStages.Length + 1]; Array.Copy(mNextStages, copy, mNextStages.Length); copy[copy.Length - 1] = stage; mNextStages = copy; // initialize the added stage, if this stage is initialized if (mInitialized) { try { stage.Initialize(); } catch (Exception) { try { stage.Shutdown(); } catch (Exception ex) { // swallow exception to avoid crashing the application, if the exception is not handled properly Debug.Fail("The pipeline stage threw an exception while shutting down", ex.ToString()); } mNextStages = oldNextStages; throw; } } } }