/// <summary>
 /// Создать сопоставление для рекурсивного обхода дерева.
 /// </summary>
 /// <typeparam name="T">Тип элемента дерева.</typeparam>
 /// <typeparam name="TApp">Тип результата.</typeparam>
 /// <param name="context">Контекст.</param>
 /// <param name="ifFunc">Функция сопоставления.</param>
 /// <param name="applyFunc">Функция применения результата.</param>
 /// <param name="getChildrenFunc">Функция получения дочерних элементов.</param>
 /// <returns>Контекст.</returns>
 public static TreeWalkContext <T, TApp> If <T, TApp>(this TreeWalkContext <T, TApp> context, Func <T, bool> ifFunc,
                                                      Func <T, TApp, TApp> applyFunc             = null,
                                                      Func <T, IEnumerable <T> > getChildrenFunc = null)
 {
     context.Functions.Add(new TreeApplyFunc <T, TApp>()
     {
         Apply       = applyFunc,
         GetChildren = getChildrenFunc,
         If          = ifFunc ?? (v => true),
         IsElse      = ifFunc == null
     });
     return(context);
 }
 private static void WalkTree <T, TApp>(TreeWalkContext <T, TApp> context, IEnumerable <T> elements,
                                        TApp currentResult)
 {
     if (elements == null || context.IsBreak)
     {
         return;
     }
     foreach (var item in elements)
     {
         if (context.IsBreak)
         {
             break;
         }
         var applyFunc = context.Functions.Where(f => !f.IsElse).FirstOrDefault(f => f.If(item)) ??
                         context.Functions.Where(f => f.IsElse).FirstOrDefault(f => f.If(item));
         if (applyFunc != null)
         {
             var newResult = (applyFunc.Apply ?? context.DefaultApply)(item, currentResult);
             var children  = (applyFunc.GetChildren ?? context.DefaultGetChildren)(item);
             WalkTree(context, children, newResult);
         }
     }
 }
 /// <summary>
 /// Установить функцию применения результата по умолчанию.
 /// </summary>
 /// <typeparam name="T">Тип элемента дерева.</typeparam>
 /// <typeparam name="TApp">Тип результата.</typeparam>
 /// <param name="context">Контекст.</param>
 /// <param name="applyFunc">Функция применения результата.</param>
 /// <returns>Контекст.</returns>
 public static TreeWalkContext <T, TApp> Apply <T, TApp>(this TreeWalkContext <T, TApp> context, Func <T, TApp, TApp> applyFunc)
 {
     context.DefaultApply = applyFunc;
     return(context);
 }
 /// <summary>
 /// Установить функцию получения дочерних элементов по умолчанию.
 /// </summary>
 /// <typeparam name="T">Тип элемента дерева.</typeparam>
 /// <typeparam name="TApp">Тип результата.</typeparam>
 /// <param name="context">Контекст.</param>
 /// <param name="getChildrenFunc">Функция получения дочерних элементов.</param>
 /// <returns>Контекст.</returns>
 public static TreeWalkContext <T, TApp> GetChildren <T, TApp>(this TreeWalkContext <T, TApp> context, Func <T, IEnumerable <T> > getChildrenFunc)
 {
     context.DefaultGetChildren = getChildrenFunc;
     return(context);
 }
 /// <summary>
 /// Создать сопоставление для рекурсивного обхода дерева для прочих случаев.
 /// </summary>
 /// <typeparam name="T">Тип элемента дерева.</typeparam>
 /// <typeparam name="TApp">Тип результата.</typeparam>
 /// <param name="context">Контекст.</param>
 /// <param name="applyFunc">Функция применения результата.</param>
 /// <param name="getChildrenFunc">Функция получения дочерних элементов.</param>
 /// <returns>Контекст.</returns>
 public static TreeWalkContext <T, TApp> Else <T, TApp>(this TreeWalkContext <T, TApp> context,
                                                        Func <T, TApp, TApp> applyFunc             = null,
                                                        Func <T, IEnumerable <T> > getChildrenFunc = null)
 {
     return(context.If(null, applyFunc, getChildrenFunc));
 }
 /// <summary>
 /// Выполнить проход по дереву.
 /// </summary>
 /// <typeparam name="T">Тип элемента дерева.</typeparam>
 /// <typeparam name="TApp">Тип результата.</typeparam>
 /// <param name="context">Контекст.</param>
 /// <returns>Результат.</returns>
 public static TApp Run <T, TApp>(this TreeWalkContext <T, TApp> context)
 {
     WalkTree(context, context.Source, context.Result);
     return(context.Result);
 }