Skip to content

Definiciones, apariciones y evaluación ​

Índice · Motivación · Anterior: reglas · Siguiente: planes

Una condición reutilizable y su aparición dentro de una composición son objetos diferentes. RuleDefinition<T, C> representa la condición identificable. RuleNode<T, C> representa una aparición de esa definición o un operador que relaciona otras apariciones.

Problema que resuelve ​

Una lista de reglas puede decir qué condiciones existen, pero no representa alternativas, condiciones de aplicabilidad ni prerrequisitos. El árbol conserva esas relaciones y permite explicar no solo qué falló, sino también qué se omitió y por qué.

El consumidor habitual no necesita construir árboles manualmente: ValidationBuilder lo hace al usar Add, Sequence, AnyOf, When y las demás operaciones. Trabaja directamente con RuleTree cuando necesites una evaluación neutral sin mensajes, identidades controladas o trazas de cada nodo.

Identidad y datos de ejecución ​

RuleDefinition.Id identifica la regla lógica, por ejemplo text.required. RuleNode.NodeId identifica una aparición dentro del árbol, por ejemplo la presencia del correo principal o la del correo de facturación. Ambas apariciones pueden reutilizar la misma definición.

Path identifica la propiedad para presentación, como BillingAddress.Email. No sustituye a ninguna de las identidades: varias reglas pueden validar la misma propiedad.

Una definición síncrona recibe Func<T, C, ConditionResult>. Una asíncrona recibe Func<T, C, CancellationToken, ValueTask<ConditionResult>>. El resultado contiene IsSatisfied y evidencia opcional de esa ejecución. La definición síncrona también expone un adaptador AsyncCondition, lo que permite al motor recorrer ambos casos mediante el mismo algoritmo.

At(nodeId, path) crea una hoja. Select<TParent>(selector) adapta la condición para extraer su valor desde un candidato más amplio. NoRuleContext representa la ausencia de contexto, y WithContext permite adaptar una definición local a un contexto que esa condición ignora.

Operadores ​

OperadorHijosSemántica
LeafNingunoEjecuta su definición
AllOfUno o másTodas las ramas aplicables deben cumplirse
AnyOfUno o másDebe cumplirse al menos una rama aplicable
NotUnoInvierte satisfecho/insatisfecho; conserva omitido
WhenCondición y contenidoEjecuta contenido si la condición se satisface; en otro caso omite el grupo
PrerequisitePrerrequisito y dependienteEjecuta dependiente si el prerrequisito se satisface; si falla, falla el grupo

Si el prerrequisito está omitido, Prerequisite también queda omitido. Una rama omitida no cuenta como un prerrequisito satisfecho. Si todas las ramas de AllOf o AnyOf están omitidas, el grupo está omitido.

El constructor del nodo comprueba la cantidad de hijos, la presencia de definición y la unicidad de NodeId en el subárbol. Copia los hijos en una colección de solo lectura.

Construcción explícita ​

csharp
using Greencore.platform.rules;
using Greencore.platform.validators;

var required = RuleDefinition.For("text.required", new RequiredRule<string?>());
var email = RuleDefinition.For("email.format", new EmailRule());
var tree = RuleTree.Require("email.sequence", required.At("email.required", "Email"), email.At("email.format", "Email"));

var evaluation = RuleEvaluator.Evaluate(tree, "", options: new(RuleExecution.Accumulate, RuleDetail.Trace));

La primera hoja falla, la segunda queda omitida con razón Prerequisite y la raíz queda insatisfecha. Este ejemplo produce una evaluación neutral; aún no asocia mensajes. Para obtener un reporte se necesitan diagnósticos, normalmente configurados mediante el builder de planes.

Rules.For<T>() ofrece el antiguo RuleTreeBuilder. Ese builder es inmutable: debes conservar el objeto retornado. Su Add permite una raíz y exige grupos explícitos para combinar nodos. Este comportamiento difiere de ValidationBuilder, que es mutable y admite varias ramas.

Motor y opciones ​

RuleEvaluator recorre el árbol secuencialmente, incluso cuando las hojas son asíncronas. No inicia todas las consultas en paralelo. Comprueba cancelación al visitar nodos y después de ejecutar cada condición; las excepciones técnicas se propagan.

Evaluate rechaza cualquier árbol marcado como asíncrono, aunque la rama asíncrona pudiera omitirse para ese candidato. EvaluateAsync admite ambos tipos de hojas.

RuleExecution.Accumulate, la opción predeterminada, continúa recorriendo un AllOf aunque una rama falle. ShortCircuit omite las ramas posteriores de ese grupo tras el primer fallo. AnyOf siempre deja de ejecutar alternativas al encontrar una satisfecha, también en modo acumulativo. Las dependencias y condiciones continúan respetándose en ambos modos.

RuleDetail.Minimal conserva principalmente las ramas necesarias para explicar un fallo. Si el grupo se satisface o se omite, no conserva sus hijos. Trace conserva los hijos y permite inspeccionar éxitos y omisiones. Una rama saltada se representa por su nodo omitido, sin expandir recursivamente todos sus descendientes.

Resultado neutral ​

RuleEvaluation conserva NodeId, RuleId, Path, Kind, Status, SkipReason, Evidence y Children. Los estados son Satisfied, Unsatisfied y Skipped. Las razones de omisión incluyen NotApplicable, ShortCircuit y Prerequisite.

La evaluación no almacena explícitamente el candidato ni el contexto. Sin embargo, si el consumidor coloca esos objetos dentro de Evidence, quedarán referenciados. Conviene usar evidencia pequeña y estable.

ComposedRule<T> adapta un árbol local síncrono a IRule<T> y considera válida cualquier raíz que no sea Unsatisfied. Es útil para reutilizar una composición donde solo se exige un booleano.

Fuentes: definiciones, nodos y evaluador.

Uso personal limitado. Uso comercial sujeto a autorización escrita.