ToExpression() recovers the predicate expression tree behind an expression-backed proposition, suitable for
handing to a query provider or composing with other System.Linq.Expressions code.
Expression<Func<TModel, bool>> ToExpression();
It is declared on the IExpressionSpec<TModel> interface, and implemented by both
ExpressionSpecBase<TModel, TMetadata> and ExpressionPolicyBase<TModel, TMetadata> — the two base types
that every Spec.From() builder path returns. See Expression Composition for how a proposition
becomes expression-backed in the first place.
Remarks
- Leaves return the original lambda instance. A proposition created directly from
Spec.From()returns exactly theExpression<Func<TModel, bool>>you passed in — no rewriting, no decomposition round-trip. - Composites recombine lazily and memoize. A proposition built by composing expression-backed operands (with
And(),Or(),Not(), etc.) does not build its combined expression untilToExpression()is first called. From then on, the result is memoized, so repeated calls return the sameExpression<Func<TModel, bool>>instance rather than rebuilding it. - No simplification is applied. The composed tree faithfully mirrors the operators used to build it — there's no De Morgan's-law rewriting or double-negation elimination. This keeps the tree predictable and lets query providers handle negation and short-circuiting nodes natively.
Basic Example
var isAdult = Spec.From((Customer c) => c.Age >= 18).Create("is adult");
Expression<Func<Customer, bool>> predicate = isAdult.ToExpression();
// c => c.Age >= 18 — the original lambda, unchanged
Composed Example
var isAdult = Spec.From((Customer c) => c.Age >= 18).Create("is adult");
var isActive = Spec.From((Customer c) => c.IsActive).Create("is active");
var eligible = isAdult & isActive;
Expression<Func<Customer, bool>> predicate = eligible.ToExpression();
// c => c.Age >= 18 And c.IsActive
Recovering the Expression Behind a Decomposed Cause
Every node produced while decomposing a Spec.From() expression — including atomic sub-expressions used to
explain a result — is itself expression-backed. This lets you recover the expression of just the
sub-proposition that caused a particular outcome, and reuse it independently:
Expression<Func<Customer, bool>> expression = c => c.Age >= 18 & c.IsActive;
var spec = expression.ToSpec();
var binary = (Motiv.Traversal.IBinaryOperationSpec<Customer, string>)spec;
var ageAtom = (IExpressionSpec<Customer>)binary.Left;
Expression<Func<Customer, bool>> ageExpression = ageAtom.ToExpression();
// c => c.Age >= 18
var customersMissingAge = dbContext.Customers.Where(ageAtom.ToExpression());
Next Steps
- Use
Where()to apply a recovered expression directly to anIQueryable<TModel>. - Read the Expression Composition overview for the composition and degradation rules that determine whether a given proposition is expression-backed.