---
title: NotificationRuleEngine
summary: API reference for NotificationRuleEngine.
status: draft
owner: SAIF.Core Documentation Team
last_reviewed: 2026-09-24
library: SAIF.Services.ClaimInfoApi.Core
reference_type: package
---

# NotificationRuleEngine

`NotificationRuleEngine` is the static evaluation-and-compilation core of this library: it evaluates every [NotificationRule](NotificationRule.md) in a [NotificationMatrix](NotificationMatrix.md) 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](../../architecture.md#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](../../operations/op-cia-01-calculate-notifications.md)).
- 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](../../operations/op-cia-02-evaluate-one-rule.md)).
- 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](../../operations/op-cia-03-compile-rule.md)).

## 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](../../business-rules.md#cia-br-001-notification-outputs-are-keyed-by-rule-position), [CIA-BR-007](../../business-rules.md#cia-br-007-only-non-null-results-become-notifications-and-the-last-one-at-a-position-wins)). 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](../../architecture.md#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](../../business-rules.md#cia-br-002-evaluation-type-is-resolved-from-rule-metadata) through [CIA-BR-006](../../business-rules.md#cia-br-006-a-true-bool-rule-without-an-out-property-falls-back-to-a-constant-out-value)).
- `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](../../business-rules.md#cia-br-009-a-matching-public-method-name-invokes-that-method) through [CIA-BR-012](../../business-rules.md#cia-br-012-an-unrecognized-operator-is-treated-as-a-method-on-the-property's-type)).
- 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`
