Expr 0.1.0

dotnet add package Expr --version 0.1.0
                    
NuGet\Install-Package Expr -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Expr" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Expr" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Expr" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Expr --version 0.1.0
                    
#r "nuget: Expr, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Expr@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Expr&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Expr&version=0.1.0
                    
Install as a Cake Tool

Expr for .NET

Expr is a safe, statically checked expression language for modern .NET. Embed user-authored rules, filters, policies, and computed values without compiling or executing arbitrary C#.

  • Compile once and evaluate concurrently with isolated runtime state.
  • Validate names, types, functions, and return values before execution.
  • Work with an immutable, public AST that can be walked, printed, and rewritten.
  • Bound evaluation with work, memory, collection, stack, regex, and cancellation limits.
  • Run on Native AOT and trimmed applications with reflection-free environment schemas.
  • Ship a single library with no third-party runtime dependencies.

Expr targets .NET 10 and C# 14.

Install

dotnet add package Expr

Quick start

For a one-off expression with no host environment:

using Expr;

object? result = ExprEngine.Evaluate("all([2, 3, 5], # > 0)");
// result is true

For repeated evaluation, describe the values visible to the expression, compile once, and reuse the resulting CompiledExpression:

using System.Collections.Generic;
using Expr;
using Expr.Configuration;
using Expr.Runtime;
using Expr.Types;

var schema = new ExprEnvironmentSchemaBuilder<OrderContext>()
    .Member("customer", static value => value.Customer, ExprTypes.String)
    .ArrayMember("prices", static value => value.Prices, ExprTypes.Float)
    .Build();

ExprConfiguration configuration = ExprConfiguration.Default
    .WithEnvironment(schema)
    .WithExpectedType(ExprTypes.Boolean);

CompiledExpression expression = ExprEngine.Compile(
    "customer == 'Ada' && sum(prices) >= 100.0",
    configuration);

bool accepted = (bool)expression.Run(
    new OrderContext("Ada", [45.0, 60.0]))!;
// accepted is true

public sealed record OrderContext(
    string Customer,
    IReadOnlyList<double> Prices);

The schema is strict: misspelled names and invalid operations fail during Compile, not in a later production evaluation. Explicit schemas are also safe for Native AOT and trimming. Conventional applications can instead create a cached reflection-based schema with ExprEnvironmentSchema.Reflect<T>().

Add application functions

Functions declare their Expr-visible signature independently of their runtime implementation, so calls remain statically checked:

using System;
using Expr;
using Expr.Configuration;
using Expr.Runtime;
using Expr.Types;

var isPreferred = new ExprFunction(
    "isPreferred",
    [new ExprFunctionOverload([ExprTypes.String], ExprTypes.Boolean)],
    static arguments => ((string)arguments[0]!).StartsWith("vip-", StringComparison.Ordinal));

ExprConfiguration configuration = ExprConfiguration.Default
    .WithFunction(isPreferred);

CompiledExpression expression = ExprEngine.Compile(
    "isPreferred('vip-123')",
    configuration);

Inspect and adapt the AST

Parsing, traversal, canonical printing, rewriting, static checking, compilation, and execution are all public APIs:

using System;
using Expr;
using Expr.Syntax;

SyntaxTree tree = ExprEngine.Parse("price * quantity");

foreach (SyntaxNode node in SyntaxWalker.Traverse(tree.Root))
{
    Console.WriteLine(node.GetType().Name);
}

SyntaxNode rewritten = new RenamePrice().Visit(tree.Root);
Console.WriteLine(SyntaxPrinter.Print(rewritten));
// unitPrice * quantity

sealed class RenamePrice : SyntaxRewriter
{
    protected override SyntaxNode VisitNode(SyntaxNode node) =>
        node is IdentifierNode { Name: "price" } identifier
            ? identifier with { Name = "unitPrice" }
            : node;
}

CompiledExpression exposes its checked SyntaxTree, SemanticModel, and immutable bytecode Program for integrations that need more than evaluation.

Bound untrusted evaluations

Every invocation accepts a cancellation token and independent runtime budgets:

using System;
using Expr.Execution;

object? result = expression.Run(
    environment,
    new ExprEvaluationOptions
    {
        WorkBudget = 100_000,
        MemoryBudget = 1_000_000,
        MaximumCollectionLength = 10_000,
        RegularExpressionTimeout = TimeSpan.FromMilliseconds(100),
    },
    cancellationToken);

See the security model before accepting expressions from an untrusted boundary.

Where to go next

The project is pre-1.0 while its public API matures. Compatibility with the Expr language is continuously checked against its upstream test corpus.

Build and contribute

dotnet restore expr-dotnet.slnx
dotnet format expr-dotnet.slnx --verify-no-changes --no-restore
dotnet build expr-dotnet.slnx --configuration Release --no-restore
dotnet test expr-dotnet.slnx --configuration Release --no-build --no-restore

See CONTRIBUTING.md for the development workflow. Maintainers can find the publication process in docs/releasing.md.

License

MIT. See LICENSE and NOTICE.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0 102 8/10/2026
0.1.0-alpha.1 50 8/10/2026