Accepted answer

You won't be able to call a "local" method within your lambda expression. If this were a simple non-nested clause, it would be relatively simple - you'd just need to change this:

private Func<TestGuy,int> GetAverageField(SomeEnum someCondition)

to this:

private Expression<Func<TestGuy,int>> GetAverageField(SomeEnum someCondition)

and then pass the result of the call into the relevant query method, e.g.

var results = query.Select(GetAverageField(fieldToAverageBy));

In this case, however, you'll need to build the whole expression tree up for the Select clause - the anonymous type creation expression, the extraction of the Key, and the extraction of the average field part. It's not going to be fun, to be honest. In particular, by the time you've built up your expression tree, that's not going to be statically typed in the same way as a normal query expression would be, due to the inability to express the anonymous type in a declaration.

If you're using .NET 4, dynamic typing may help you, although you'd pay the price of not having static typing any more, of course.

One option (horrible though it may be) would be try to use a sort of "template" of the anonymous type projection expression tree (e.g. always using a single property), and then build a copy of that expression tree, inserting the right expression instead. Again, it's not going to be fun.

Marc Gravell may be able to help more on this - it does sound like the kind of thing which should be possible, but I'm at a loss as to how to do it elegantly at the moment.


Eh? the parameter to Queryable.Average is not Func<T, U>. It's Expression<Func<T, U>>

The way to do this is:

private Expression<Func<TestGuy,int>> GetAverageExpr(SomeEnum someCondition)
case SomeEnum.Interesting:
  return tg => tg.InterestingValue;
case SomeEnum.Other:
  return tg => tg.OtherValue;
throw new InvalidOperationException("Not in my example!");

Followed by:

Expression<Func<TestGuy, int>> averageExpr = GetAverageExpr(someCondition);
var byCity = testGuys
  .GroupBy(c => c.City)
  .Select(g => new { City = g.Key, Avg = g.Average(averageExpr) });

Related Articles