0

As per requirement I want to create a dynamic lambda expression using C#.

For example I want to generate the dynamic query like

Employee. Address[1].City

How can I do this? Please note that the property is a dynamic one.

I have tried this code

var item = Expression.Parameter(typeof(Employee), "item");

Expression prop = Expression.Property(item, "Address", new Expression[] { Expression.Constant[1] });
prop = Expression.Property(prop, "City");

var propValue = Expression.Constant(constraintItem.State);
var expression = Expression.Equal(prop, propValue);
var lambda = Expression.Lambda<Func<Line, bool>>(expression, item);

But it did not work.

Any help would be appreciated.

Thanks.

1
  • Is Address an indexer? If it's an array, use Expression.ArrayIndex, If it's just a list with an indexer, retrieve the list using an unindexed Expression.Property, and then apply an indexed property retrieval expression on it's Items property. Commented Dec 6, 2015 at 13:47

1 Answer 1

3

You "dynamic query" expression (which is not really a query, it's a simple MemberExpression) can be produced as follows:

ParameterExpression param = Expression.Parameter(typeof(Employee), "item");
MemberExpression address = Expression.Property(param, "Address");
BinaryExpression indexedAddress = Expression.ArrayIndex(address, Expression.Constant(1));
MemberExpression city = Expression.Property(indexedAddress, "City"); // Assuming "City" is a string.

// This will give us: item => item.Address[1].City
Expression<Func<Employee, string>> memberAccessLambda = Expression.Lambda<Func<Employee, string>>(city, param);

If you want an actual predicate to use as part of your query, you just wrap the MemberExpression with a relevant compare expression, i.e.

BinaryExpression eq = Expression.Equal(city, Expression.Constant("New York"));

// This will give us: item => item.Address[1].City == "New York"
Expression<Func<Employee, bool>> predicateLambda = Expression.Lambda<Func<Employee, bool>>(eq, param);

In terms of your code: not sure why you're creating a lambda where the delegate type is Func<Line, bool> when the input is clearly expected to be Employee. Parameter type must always match the delegate signature.

EDIT

Non-array indexer access example:

ParameterExpression param = Expression.Parameter(typeof(Employee), "item");
MemberExpression address = Expression.Property(param, "Address");

IndexExpression indexedAddress = Expression.MakeIndex(
    address,
    indexer: typeof(List<string>).GetProperty("Item", returnType: typeof(string), types: new[] { typeof(int) }),
    arguments: new[] { Expression.Constant(1) }
);

// Produces item => item.Address[1].
Expression<Func<Employee, string>> lambda = Expression.Lambda<Func<Employee, string>>(indexedAddress, param);

// Predicate (item => item.Address[1] == "Place"):
BinaryExpression eq = Expression.Equal(indexedAddress, Expression.Constant("Place"));
Expression<Func<Employee, bool>> predicateLambda = Expression.Lambda<Func<Employee, bool>>(eq, param);
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your reply. A slight change in requirement. Address is a List<String> property in Employee class.
I am getting following error "An unhandled exception of type 'System.ArgumentException' occurred in System.Core.dll"
requirement is generate the query for x.Address[1]=='Place'. Thanks!!
That's because ArrayIndex only works on arrays (not lists). I'll amend my code and I hope you'll be able to take it from there (at this point it is not really clear what kind of predicate you will be producing using your List<string>).
Thanks for clarifying. Amended.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.