Lambda Expression
Nested Property
C#
String Parsing
.NET

Construct LambdaExpression for nested property from string

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Building a LambdaExpression from a nested property path string is a common requirement in dynamic filtering, sorting, and API query builders. Typical input looks like "Address.City.Name", and the goal is to produce an expression equivalent to x => x.Address.City.Name. The challenge is making this dynamic while keeping type safety, null handling, and provider compatibility.

Why Dynamic Nested Expressions Are Useful

You need this pattern when property names come from runtime input rather than compile-time code.

Typical use cases:

  • dynamic grid sorting in backend APIs
  • user-defined filters in admin tools
  • generic repository search helpers
  • rule engines driven by configuration

Expression trees are preferred over reflection-only approaches when integrating with LINQ providers such as Entity Framework.

Core Expression-Building Pattern

The standard approach:

  1. create parameter expression for root type
  2. split path by dot
  3. chain Expression.PropertyOrField
  4. wrap in lambda
csharp
1using System;
2using System.Linq.Expressions;
3
4public static class ExpressionBuilder
5{
6    public static LambdaExpression BuildPropertyLambda(Type rootType, string path)
7    {
8        if (string.IsNullOrWhiteSpace(path))
9            throw new ArgumentException("Path is required", nameof(path));
10
11        var parameter = Expression.Parameter(rootType, "x");
12        Expression body = parameter;
13
14        foreach (var segment in path.Split('.'))
15        {
16            body = Expression.PropertyOrField(body, segment);
17        }
18
19        var delegateType = typeof(Func<,>).MakeGenericType(rootType, body.Type);
20        return Expression.Lambda(delegateType, body, parameter);
21    }
22}

This returns a strongly typed lambda expression at runtime.

Generic Typed Helper

Most call sites need a generic form compatible with IQueryable<T>.

csharp
1using System;
2using System.Linq.Expressions;
3
4public static class ExpressionBuilder
5{
6    public static Expression<Func<T, object?>> BuildObjectLambda<T>(string path)
7    {
8        var parameter = Expression.Parameter(typeof(T), "x");
9        Expression body = parameter;
10
11        foreach (var segment in path.Split('.'))
12        {
13            body = Expression.PropertyOrField(body, segment);
14        }
15
16        // box value types so return type can be object
17        if (body.Type.IsValueType)
18            body = Expression.Convert(body, typeof(object));
19
20        return Expression.Lambda<Func<T, object?>>(body, parameter);
21    }
22}

This helper works for sorting scenarios where one object-returning selector is acceptable.

Applying the Expression to Sorting

csharp
1using System.Linq;
2
3public static IQueryable<T> OrderByPath<T>(IQueryable<T> query, string path)
4{
5    var lambda = ExpressionBuilder.BuildObjectLambda<T>(path);
6    return query.OrderBy(lambda);
7}

For best SQL translation in ORMs, a fully typed selector may perform better than object conversion. Consider generating typed method calls by final property type when provider translation is sensitive.

Null-Safe Navigation Considerations

Simple chained property access can throw null reference exceptions when evaluated in-memory. If null-safe behavior is required, build conditional expressions per segment.

Conceptually:

  • before accessing next segment, check current expression for null
  • if null, return default
  • else access next property

This increases complexity, but can prevent runtime exceptions in non-provider execution paths.

A lightweight compromise is validating path only for query providers where translation handles null semantics.

Path Validation and Security

Never trust raw client path strings without validation. A malformed or unexpected path can cause runtime failures or access unintended fields.

Recommended validation:

  • allow-list sortable and filterable paths
  • reject empty segments and invalid characters
  • verify each segment exists on current type
  • return clear errors for unknown paths

Validation helper concept:

csharp
1using System;
2using System.Reflection;
3
4public static Type ValidatePath(Type rootType, string path)
5{
6    var type = rootType;
7    foreach (var segment in path.Split('.'))
8    {
9        var member = type.GetProperty(segment, BindingFlags.Public | BindingFlags.Instance)
10                     ?? (MemberInfo?)type.GetField(segment, BindingFlags.Public | BindingFlags.Instance);
11
12        if (member == null)
13            throw new InvalidOperationException($"Unknown segment: {segment}");
14
15        type = member is PropertyInfo pi ? pi.PropertyType : ((FieldInfo)member).FieldType;
16    }
17
18    return type;
19}

Provider Compatibility Tips

Entity Framework and other query providers cannot translate every custom expression shape. Keep generated expressions simple:

  • use direct member access when possible
  • avoid unsupported local method calls in expression body
  • test representative paths against real provider

If translation fails, evaluate whether in-memory fallback is acceptable for your dataset size.

Testing Strategy

Add unit tests for:

  • valid single-segment and nested paths
  • invalid segment names
  • value type and reference type properties
  • sort behavior with generated selector
  • null-containing object graphs if using in-memory evaluation

Expression builders are infrastructure code and deserve focused tests because many query endpoints rely on them.

Common Pitfalls

  • Building expressions from unvalidated user path input.
  • Returning object-boxed expressions in scenarios where provider translation requires concrete types.
  • Ignoring null intermediate properties when evaluating outside query providers.
  • Using reflection only and losing LINQ translation capabilities.
  • Allowing arbitrary path access that exposes internal model structure.

Summary

  • Dynamic nested lambda construction is powerful for runtime-driven querying.
  • Build expressions by chaining property access from parameter to final segment.
  • Validate paths and constrain allowed fields for reliability and security.
  • Keep expression shape provider-friendly for ORM translation.
  • Add tests early because one builder usually impacts many query endpoints.

Course illustration
Course illustration

All Rights Reserved.