/// <inheritdoc/>
        public virtual void DeriveWantAction <TFactRule, TFactRuleCollection, TWantAction, TFactContainer>(List <DeriveWantActionRequest <TFactRule, TFactRuleCollection, TWantAction, TFactContainer> > requests)
            where TFactRule : IFactRule
            where TFactRuleCollection : IFactRuleCollection <TFactRule>
            where TWantAction : IWantAction
            where TFactContainer : IFactContainer
        {
            Validate(requests);

            var treesByActions     = new Dictionary <WantActionInfo <TWantAction, TFactContainer>, List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > >();
            var deriveErrorDetails = new List <DeriveErrorDetail>();


            foreach (DeriveWantActionRequest <TFactRule, TFactRuleCollection, TWantAction, TFactContainer> request in requests)
            {
                var context = request.Context;

                if (!context.WantAction.Option.HasFlag(FactWorkOption.CanExecuteSync))
                {
                    deriveErrorDetails.Add(new DeriveErrorDetail(
                                               ErrorCode.InvalidOperation,
                                               ErrorResources.OnWantActionCannotBePerformedSynchronously(context.WantAction),
                                               context.WantAction,
                                               context.Container,
                                               null));
                    continue;
                }

                var requestForAction = new BuildTreesForWantActionRequest <TFactRule, TWantAction, TFactContainer>
                {
                    Context   = context,
                    FactRules = request
                                .Rules
                                .FindAll(factRule => factRule.Option.HasFlag(FactWorkOption.CanExecuteSync))
                                .SortByDescending(r => r, context.SingleEntity.GetRuleComparer <TFactRule, TWantAction, TFactContainer>(context)),
                };

                if (context.TreeBuilding.TryBuildTreesForWantAction(requestForAction, out var resultForAction))
                {
                    treesByActions.Add(resultForAction.WantActionInfo, resultForAction.TreesResult);
                }
                else
                {
                    deriveErrorDetails.Add(resultForAction.DeriveErrorDetail);
                }
            }

            // Check that we were able to adequately build the tree.
            if (deriveErrorDetails.Count != 0)
            {
                throw CommonHelper.CreateDeriveException(deriveErrorDetails);
            }

            foreach (var item in treesByActions)
            {
                item.Key.Context.TreeBuilding.CalculateTreeAndDeriveWantFacts(item.Key, item.Value);
            }
        }
        /// <inheritdoc/>
        public virtual async ValueTask DeriveWantActionAsync <TFactRule, TFactRuleCollection, TWantAction, TFactContainer>(List <DeriveWantActionRequest <TFactRule, TFactRuleCollection, TWantAction, TFactContainer> > requests)
            where TFactRule : IFactRule
            where TFactRuleCollection : IFactRuleCollection <TFactRule>
            where TWantAction : IWantAction
            where TFactContainer : IFactContainer
        {
            Validate(requests);

            var treesByActions     = new Dictionary <WantActionInfo <TWantAction, TFactContainer>, List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> > >();
            var deriveErrorDetails = new List <DeriveErrorDetail>();


            foreach (DeriveWantActionRequest <TFactRule, TFactRuleCollection, TWantAction, TFactContainer> request in requests)
            {
                var context = request.Context;

                var requestForAction = new BuildTreesForWantActionRequest <TFactRule, TWantAction, TFactContainer>
                {
                    Context   = context,
                    FactRules = request
                                .Rules
                                .SortByDescending(r => r, context.SingleEntity.GetRuleComparer <TFactRule, TWantAction, TFactContainer>(context)),
                };

                if (context.TreeBuilding.TryBuildTreesForWantAction(requestForAction, out var resultForAction))
                {
                    treesByActions.Add(resultForAction.WantActionInfo, resultForAction.TreesResult);
                }
                else
                {
                    deriveErrorDetails.Add(resultForAction.DeriveErrorDetail);
                }
            }

            // Check that we were able to adequately build the tree.
            if (deriveErrorDetails.Count != 0)
            {
                throw CommonHelper.CreateDeriveException(deriveErrorDetails);
            }

            foreach (var item in treesByActions)
            {
                await item.Key.Context.TreeBuilding.CalculateTreeAndDeriveWantFactsAsync(item.Key, item.Value);
            }
        }
        /// <inheritdoc/>
        public bool TryBuildTreesForWantAction <TFactRule, TWantAction, TFactContainer>(BuildTreesForWantActionRequest <TFactRule, TWantAction, TFactContainer> request, out BuildTreesForWantActionResult <TFactRule, TWantAction, TFactContainer> result)
            where TFactRule : IFactRule
            where TWantAction : IWantAction
            where TFactContainer : IFactContainer
        {
            var context = request.Context;
            var deriveFactErrorDetails = new List <DeriveFactErrorDetail>();
            var wantActionInfo         = new WantActionInfo <TWantAction, TFactContainer>
            {
                BuildFailedConditions  = new List <IBuildConditionFact>(),
                BuildSuccessConditions = new List <IBuildConditionFact>(),
                RuntimeConditions      = new List <IRuntimeConditionFact>(),
                Context = context,
            };

            result = new BuildTreesForWantActionResult <TFactRule, TWantAction, TFactContainer>
            {
                TreesResult    = new List <TreeByFactRule <TFactRule, TWantAction, TFactContainer> >(),
                WantActionInfo = wantActionInfo,
            };

            foreach (var needFactType in context.SingleEntity.GetRequiredTypesOfFacts(context.WantAction, context))
            {
                if (needFactType.IsFactType <IBuildConditionFact>())
                {
                    if (wantActionInfo.BuildSuccessConditions.Exists(fact => context.Cache.GetFactType(fact).EqualsFactType(needFactType)) || wantActionInfo.BuildFailedConditions.Exists(fact => context.Cache.GetFactType(fact).EqualsFactType(needFactType)))
                    {
                        continue;
                    }

                    var condition = Factory.CreateObject(
                        type => type.CreateBuildConditionFact <IBuildConditionFact>(),
                        needFactType
                        );

                    if (condition.Condition(context.WantAction, context, ct => ct.WantAction.GetCompatibleRulesEx(request.FactRules, context)))
                    {
                        result.WantActionInfo.BuildSuccessConditions.Add(condition);
                    }
                    else
                    {
                        result.WantActionInfo.BuildFailedConditions.Add(condition);
                        deriveFactErrorDetails.Add(new DeriveFactErrorDetail(needFactType, null));
                    }

                    continue;
                }

                if (needFactType.IsFactType <IRuntimeConditionFact>())
                {
                    var condition = Factory.CreateObject(
                        type => type.CreateRuntimeConditionFact <IRuntimeConditionFact>(),
                        needFactType);

                    result.WantActionInfo.RuntimeConditions.Add(condition);

                    continue;
                }

                var requestFactType = new BuildTreeForFactInfoRequest <TFactRule, TWantAction, TFactContainer>
                {
                    WantFactType = needFactType,
                    Context      = new FactRulesContext <TFactRule, TWantAction, TFactContainer>
                    {
                        Cache     = context.Cache,
                        Container = context.Container,
                        FactRules = context
                                    .WantAction
                                    .GetCompatibleRulesEx(request.FactRules, context),
                        SingleEntity = context.SingleEntity,
                        TreeBuilding = context.TreeBuilding,
                        WantAction   = context.WantAction,
                        Engine       = context.Engine,
                    },
                };

                if (context.TreeBuilding.TryBuildTreeForFactInfo(requestFactType, out var resultTree, out var errorList))
                {
                    result.TreesResult.Add(resultTree);
                }