Skip to content

NotificationRuleEngine

NotificationRuleEngine is the static evaluation-and-compilation core of this library: it evaluates every NotificationRule in a NotificationMatrix against a caller-supplied model of any type T by building and compiling a LINQ expression tree for each rule on every call. It holds no instance state, though the class itself is not declared static, and it recompiles each rule's expression on every invocation with no delegate cache — a known performance characteristic documented in Architecture: Design constraints.

Purpose

  • Provide the single public entry point, CalculateNotifications<T>, that iterates a matrix's rules, evaluates each against a model, and collects the non-null results keyed by rule position (OP-CIA-01).
  • Dispatch each rule to an int, bool, or string evaluation path based on its resolved Type, including the recursive out-property resolution for conditional rules (OP-CIA-02).
  • Build a LINQ expression tree from a rule's member name, operator name, and target value, and compile it into a runnable delegate on every call, with no caching (OP-CIA-03).

Context

  • Namespace: SAIF.Services.ClaimInfoApi.Core
  • Assembly/package: SAIF.Services.ClaimInfoApi.Core.dll, packaged inside the SAIF.SAIFCode.Core NuGet package

Public members

Member Signature Purpose
CalculateNotifications<T> public static NotificationResult[] CalculateNotifications<T>(T model, NotificationMatrix matrix) Evaluates every rule in matrix.Rules against model and returns the non-null results, one per distinct rule position, with the last non-null value at a position winning (CIA-BR-001, CIA-BR-007). Throws NullReferenceException if matrix.Rules is null.
CompileRule<T,TResult> public static Func<T, TResult> CompileRule<T, TResult>(NotificationRule r) Builds a LINQ expression tree from r's metadata and compiles it into a delegate of type Func<T,TResult>; recompiles from scratch on every call with no cache (Architecture: Design constraints).

Behavioral notes

  • CalculateNotification<T> (private) resolves rule.Type and dispatches to the int, bool, or string branch; an unresolvable TypeName falls through to the string branch rather than failing (CIA-BR-002 through CIA-BR-006).
  • BuildExpr<T> (private) chooses the first matching branch — a public method match, a null operator (property read), an ExpressionType-parseable operator (binary comparison), or a method on the property's type — to construct the expression body (CIA-BR-009 through CIA-BR-012).
  • There is no validation or try/catch anywhere in this class. An unknown member name, a non-convertible TargetValue, or a delegate type mismatch all propagate as unhandled exceptions to the caller (NullReferenceException, ArgumentNullException, ArgumentException, InvalidCastException, or FormatException, depending on the failure)*.
  • Result array order from CalculateNotifications<T> follows Dictionary<string, NotificationResult> enumeration order, which is not formally guaranteed*.

Constraints and usage notes

  • Callers must ensure matrix.Rules is non-null before invoking CalculateNotifications<T>; there is no internal guard.
  • Because CompileRule<T,TResult> performs no caching, calling CalculateNotifications<T> repeatedly with large rule sets or in hot paths recompiles every rule's expression tree each time — treat this as a performance constraint when designing callers, not a tunable option in this library*.
  • T can be any type; whether a given rule succeeds depends entirely on runtime reflection finding the named member/method on T — there is no compile-time verification that a NotificationMatrix is compatible with a given model type.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Services/SAIF.Services.ClaimInfoApi.Core/NotificationRuleEngine.cs