public override IEnumerable <string> Process()
        {
            PrepareBeforeProcessing();

            var result         = new ConcurrentBag <string>();
            var taskProcessors = GetTaskProcessors();

            if (ParallelMode && taskProcessors.Count > 1)
            {
                var exceptions = new ConcurrentQueue <Exception>();

                int totalCount = taskProcessors.Count;

                Progress.SetRange(0, totalCount);

                var finishedProcessors = new ConcurrentList <IParallelTaskProcessor>();
                var curProcessors      = new ConcurrentList <IParallelTaskProcessor>();

                Progress.SetMessage("Start processing ... ");
                DateTime start = DateTime.Now;
                Parallel.ForEach(taskProcessors, Option, (processor, loopState) =>
                {
                    curProcessors.Add(processor);

                    processor.LoopState = loopState;
                    processor.Progress  = Progress;
                    try
                    {
                        var curResult = processor.Process();

                        foreach (var f in curResult)
                        {
                            result.Add(f);
                        }

                        curProcessors.Remove(processor);
                        finishedProcessors.Add(processor);

                        if (!Progress.IsConsole())
                        {
                            Progress.SetPosition(finishedProcessors.Count);
                        }

                        DateTime end  = DateTime.Now;
                        var cost      = end - start;
                        var expectEnd = start.AddSeconds(cost.TotalSeconds / finishedProcessors.Count * totalCount);
                        Progress.SetMessage("{0} threads running, {1} / {2} finished, expect to be end at {3}", curProcessors.Count, finishedProcessors.Count, totalCount, expectEnd);
                    }
                    catch (Exception e)
                    {
                        exceptions.Enqueue(e);
                        loopState.Stop();
                    }

                    GC.Collect();
                });

                if (Progress.IsCancellationPending())
                {
                    throw new UserTerminatedException();
                }

                if (exceptions.Count > 0)
                {
                    if (exceptions.Count == 1)
                    {
                        throw exceptions.First();
                    }
                    else
                    {
                        StringBuilder sb = new StringBuilder();
                        foreach (var ex in exceptions)
                        {
                            sb.AppendLine(ex.ToString());
                        }
                        throw new Exception(sb.ToString());
                    }
                }
            }
            else
            {
                for (int i = 0; i < taskProcessors.Count; i++)
                {
                    if (Progress.IsCancellationPending())
                    {
                        throw new UserTerminatedException();
                    }

                    string rootMsg = MyConvert.Format("{0} / {1}", i + 1, taskProcessors.Count);

                    Progress.SetMessage(1, rootMsg);
                    var processor = taskProcessors[i];
                    processor.Progress = Progress;

                    var curResult = processor.Process();

                    foreach (var f in curResult)
                    {
                        result.Add(f);
                    }
                }
            }

            DoAfterProcessing(result);

            return(result);
        }
        public override IEnumerable <string> Process(string aPath)
        {
            PrepareBeforeProcessing(aPath);

            var result = new ConcurrentBag <string>();

            if (ParallelMode && _sourceFiles.Count > 1)
            {
                var exceptions = new ConcurrentQueue <Exception>();

                int totalCount = _sourceFiles.Count;

                Progress.SetRange(0, totalCount);

                var curFiles      = new ConcurrentList <string>();
                var finishedFiles = new ConcurrentList <string>();
                var curProcessors = new ConcurrentList <IParallelTaskFileProcessor>();

                Parallel.ForEach(_sourceFiles, Option, (sourceFile, loopState) =>
                {
                    curFiles.Add(sourceFile);

                    Progress.SetMessage("Processing {0}, finished {1} / {2}", curFiles.Count, finishedFiles.Count, totalCount);

                    IParallelTaskFileProcessor processor = GetTaskProcessor(aPath, sourceFile);

                    if (processor == null)
                    {
                        curFiles.Remove(sourceFile);
                        finishedFiles.Add(sourceFile);
                        return;
                    }

                    processor.LoopState = loopState;
                    processor.Progress  = Progress;

                    curProcessors.Add(processor);
                    try
                    {
                        var curResult = processor.Process(sourceFile);

                        foreach (var f in curResult)
                        {
                            result.Add(f);
                        }

                        curFiles.Remove(sourceFile);
                        finishedFiles.Add(sourceFile);

                        Progress.SetPosition(finishedFiles.Count);
                        Progress.SetMessage("Processing {0}, finished {1} / {2}", curFiles.Count, finishedFiles.Count, totalCount);
                    }
                    catch (Exception e)
                    {
                        exceptions.Enqueue(e);
                        loopState.Stop();
                    }

                    GC.Collect();
                });

                if (Progress.IsCancellationPending())
                {
                    throw new UserTerminatedException();
                }

                if (exceptions.Count > 0)
                {
                    if (exceptions.Count == 1)
                    {
                        throw exceptions.First();
                    }
                    else
                    {
                        StringBuilder sb = new StringBuilder();
                        foreach (var ex in exceptions)
                        {
                            sb.AppendLine(ex.ToString());
                        }
                        throw new Exception(sb.ToString());
                    }
                }
            }
            else
            {
                for (int i = 0; i < _sourceFiles.Count; i++)
                {
                    if (Progress.IsCancellationPending())
                    {
                        throw new UserTerminatedException();
                    }

                    string rootMsg = MyConvert.Format("{0} / {1} : {2}", i + 1, _sourceFiles.Count, _sourceFiles[i]);

                    Progress.SetMessage(1, rootMsg);

                    IParallelTaskFileProcessor processor = GetTaskProcessor(aPath, _sourceFiles[i]);
                    processor.Progress = Progress;

                    var curResult = processor.Process(_sourceFiles[i]);

                    foreach (var f in curResult)
                    {
                        result.Add(f);
                    }
                }
            }

            DoAfterProcessing(aPath, result);

            return(result);
        }