9ee1
9ee1

Reputation: 1078

Modify Dynamic Property Selector Lambda

I wrote a small method that can build a property selector lambda from a string - something like what Dynamic LINQ does and a million other examples here on Stack Overflow.

For example, given this Expressions.PropertySelector<Type, PropertyType>("Source.Date"), it would return a Func, if compiled, similar to this (Type) => type.Source.Date.

Anyway I ran into a situation where not only do I need to select the property, but also invoke a method defined by its type.

So for example, I want the equivalent of this: (Type) => Type.Source.Date.ToString("Y"). I know I can probably modify my PropertySelector method to detect a method call and build the appropriate expression, but I am curious if there is a better way.

For those curious why I need this: Basically its for an Entity Framework backed repository I am building. I have a method that allows the caller to pass a lambda to represent a property to group on. The caller themselves constructs the lambda based on user input. So I figured doing it this way would be the best approach.

But, for example, what if the property to group on is a DateTime. And I would to group on its formatted string.

What's the best approach to handle a scenario like this? Ideally, I would like the caller, after the expression is dynamically built, to modify it.

Upvotes: 2

Views: 667

Answers (1)

svick
svick

Reputation: 244848

If I understand you correctly, you have two expressions: one from T1 to T2, the second from T2 to T3 and you want to combine them into one (from T1 to T3). You can use LINQKit to do this:

public static Expression<Func<T1, T3>> CombineExpressions<T1, T2, T3>(
    Expression<Func<T1, T2>> first, Expression<Func<T2, T3>> second)
{
    Expression<Func<T1, T3>> result = x => second.Invoke(first.Invoke(x));
    // I think double Expand here is necessary because of Invoke inside Invoke
    return result.Expand().Expand();
}

For example:

Expression<Func<Person, DateTime>> getDateExpression =
    person => person.DOB;
Expression<Func<DateTime, string>> dateFormatExpression =
    date => date.ToString("Y");
Expression<Func<Person, string>> result =
    CombineExpressions(getDateExpression, dateFormatExpression);

Here, result contains the expression (Person x) => x.DOB.ToString("Y").

You can build one or both of the expressions dynamically, it won't change how the combining works.

Upvotes: 2

Related Questions