LINQ is powerful for querying data, but what happens when you need dynamic filtering?
Imagine your users want to create custom filters like: "Show me all products under $50" or "Sort products by price, but only if they were created this month."
Traditional LINQ queries are static, written at compile time. When you need dynamic queries based on user input, you're stuck with complex conditional logic or manual query building.
That's where the C# Eval Expression Library comes in. It extends LINQ with dynamic capabilities while keeping the familiar syntax and performance.
In today's post, we'll explore how to use it for:
- Eval.Execute - Runtime code execution
- WhereDynamic - Dynamic filtering
- OrderByDynamic - Dynamic sorting
- LINQ Execute - Complete query control
- EvalContext - Security and control
- Variable passing - Flexible expressions
Getting started
To get started with C# Eval Expression, you'll first need to install the necessary NuGet package. You can do this via the NuGet Package Manager or by running the following command in the Package Manager Console:
Install-Package Z.Expressions.Eval
C# Eval Expression is compatible with:
- .NET 5+
- .NET Framework 4.0+
Eval Expressions
Beyond LINQ Dynamic methods, the C# Eval Expression Library also provides powerful capabilities for general runtime code execution.
This allows you to execute C# code dynamically at runtime, opening up possibilities for dynamic scripting, configuration-driven logic and more flexible application behavior.
Eval.Execute
The Eval.Execute method is the foundation for runtime code execution. It allows you to execute any valid C# expression and return the result.
var result = Eval.Execute("2 + 3 * 4");
Console.WriteLine(result);
var message = Eval.Execute("'Hello ' + 'World'");
Console.WriteLine(message);
var tomorrow = Eval.Execute("DateTime.Now.AddDays(1)");
Console.WriteLine(tomorrow);
var isValid = Eval.Execute("DateTime.Now.Hour >= 9 && DateTime.Now.Hour <= 17");
Console.WriteLine(isValid);
Eval.Execute with Variables
To fully leverage Eval.Execute, you can use it with variables.
Passing variables into your dynamic expressions makes them far more flexible, allowing you to use external data within your runtime expressions.
There are several ways to do this:
Using Anonymous Objects
Anonymous objects are a quick and easy way to pass values into an expression.
var user = new { Name = "John", Age = 30, Salary = 50000 };
var isEligible = Eval.Execute("Age >= 18 && Salary > 40000", user);
Console.WriteLine(isEligible);
Using a Dictionary
A Dictionary gives you full flexibility, especially when variable names and values are not known until runtime.
var parameters = new Dictionary<string, object>
{
{ "x", 10 },
{ "y", 5 },
{ "operation", "multiply" }
};
var result = Eval.Execute("operation == 'multiply' ? x * y : x + y", parameters);
Console.WriteLine(result);
Using Class Instances
You can also pass class instances, making their properties directly accessible inside the expression.
var calculator = new Calculator { Value1 = 15, Value2 = 3 };
var calculation = Eval.Execute("Value1 / Value2 + 2", calculator);
Console.WriteLine(calculation);
Using ExpandoObject
An ExpandoObject allows you to create a dynamic structure at runtime without defining a class beforehand.
dynamic expando = new ExpandoObject();
expando.Value1 = 8;
expando.Value2 = 4;
expando.Operation = "divide";
var expandoResult = Eval.Execute(
"Operation == "divide" ? Value1 / Value2 : Value1 * Value2",
(object)expando);
Console.WriteLine(expandoResult);
EvalContext for Safe Dynamic Code Execution
For more control and security, you can use EvalContext to configure the execution environment.
This allows you to restrict what code can be executed and provide better security for dynamic code execution.
var context = new EvalContext();
context.SafeMode = true;
context.UnregisterAll();
context.RegisterDefaultAliasSafe();
context.RegisterType(typeof(Math));
var userData = new { Name = "Alice", Score = 85 };
context.RegisterLocalVariable("Score", userData.Score);
var grade = context.Execute<string>("Score >= 90 ? "A" : Score >= 80 ? "B" : "C"");
Console.WriteLine(grade);
var result = context.Execute<double>("Math.Sqrt(16) + 5");
Console.WriteLine(result);
The EvalContext provides several security and configuration options:
- SafeMode - Enables restricted code execution for better security
- UnregisterAll() - Unregisters all types, variables, and aliases that the context already registered, restoring it to a clean state before adding only what you consider safe
- RegisterDefaultAliasSafe() - Registers safe default aliases for common operations
- RegisterType() - Registers specific types that can be used in expressions
- RegisterLocalVariable() - Registers local variables that can be referenced in expressions
WhereDynamic Method
The Where can't have a dynamic expression.
However, the WhereDynamic method allows us to easily apply dynamic filtering.
Under the hood, it generates the proper lambda expression and calls the actual LINQ Where method.
In this example, we will filter products from the database depending on a custom filter entered by the end-user input.
var products = context
.Products
.WhereDynamic(x => "x.Price <= 50")
.ToList();
// ...or...
var products = context
.Products
.WhereDynamic("x => x.Price <= 50")
.ToList();
As shown above, you can pass parameters in two ways:
- x => "expression"
- "x => expression"
Personally, I prefer having the entire expression as a string.
That said, there’s no recommended way, both approaches are valid and supported. Choose whichever feels simpler and more readable to you.
Dynamic Ordering
Similar to WhereDynamic, we can order ascading or descading dynamically with:
- OrderByDynamic
- OrderByDescendingDynamic
It works by creating a lambda expression under the hood and calling the standard ordering LINQ method.
Here's an example where we sort products by their price:
var products = context
.Products
.OrderByDynamic(x => "x.Price")
.ToList();
var products = context
.Products
.OrderByDescendingDynamic("x => x.Price")
.ToList();
Like WhereDynamic, you can pass the lambda expression either outside or inside the string.
You can also combine these methods to create complex dynamic queries:
var products = context
.Products
.WhereDynamic(x => "x.Price <= 100")
.OrderByDescendingDynamic(x => "x.Price")
.Take(10)
.ToList();
This query filters products under $100, sorts them by price in descending order and takes the top 10 results.
LINQ Execute Method
The LINQ Execute method is the most flexible of our LINQ Dynamic methods. Not only can the user filter a query dynamically, but he can do whatever he wants in the expression.
In this example, we will query products in the database and:
- Filter the products to return
- Order the returned products
- Select columns that we return
var products = context
.Products
.Execute<IEnumerable<Product>>("Where(x => x.Price <= 100).OrderBy(x => x.Price).ToList()");
One major difference with the Execute method is that you call the LINQ method directly and not the dynamic counterpart.
It makes sense as the Execute method behavior is really to execute C# code at runtime.
LINQ Execute with IQueryable
The LINQ Execute method is particularly powerful when used with IQueryable, as it allows you to build complex dynamic queries and add additional LINQ operations after the Execute call. The query will be optimized and translated to efficient SQL.
var query = context.Products.AsQueryable();
var products = query
.Execute<IQueryable<Product>>("Where(x => x.Price <= 100).OrderByDescending(x => x.Price)")
.Take(10)
.ToList();
Conclusion
Dynamic filtering and runtime execution unlock a new level of flexibility in your applications.
Instead of writing endless conditional LINQ statements, the C# Eval Expression Library lets you build powerful queries with minimal effort.
The Execute method gives you complete query control at runtime, while EvalContext ensures security when running dynamic code.
This library works great with Entity Framework Core, maintaining SQL translation capabilities while adding dynamic query building.
If you want to check out examples I created, you can find the source code here:
Source CodeI hope you enjoyed it, subscribe and get a notification when a new blog is up!
