2

I have been playing with expression trees this week and I am wondering why this expression produces error when ran.

var pe = Expression.Parameter(typeof(Nullable<DateTime>));

var ex = Expression.Lambda<Func<DateTime?, bool>>(
   (Expression<Func<DateTime?, bool>>) (x => x.HasValue), pe);

The idea behind this is to write expression trees with a mix of expression tree api and linq expressions. It would make things easier to write for example instead of calling Expression.Property(...,..) I would just have x => x.Prop, right?

In my example instead of this Expression.Property(..hasvalue..) I would have this: x.HasValue. It would save me time on writing and it would look shorter, right?

The question is, is this possible?

I guess I might be missing something about

Expression<Func<DateTime?, bool>> foo = x => x.HasValue (this works)

and

Func<DateTime?, bool> bar = x => x.HasValue (this works too)

What is happening behind those two? Are they the same?

Can linq expression be mixed with standard expression tree api???

Please enlighten me on this, I feel lost. :)

4

1 回答 1

1

This is a good question. Your two quotations

Expression<Func<DateTime?, bool>> foo = x => x.HasValue

and

Func<DateTime?, bool> bar = x => x.HasValue

are examples of homoiconicity: the same symbol (in your case x => x.HasValue) stands for two very different objects. In the first case, it indicates an expression tree; in the second, a function. The former can be compiled down to the latter, but they are different types with different purposes. It is the declaration in your case that tells the compiler which version to go for. In the absence of this context, the compiler cannot read your mind and decides to bail out instead. That's why this won't compile:

var bat = x => x.HasValue;

And that is why your statement won't compile.

Homoiconicity is what makes IQueryable and IEnumerable look so similar. When you invoke

var filteredCollection = myCollection.Where(e => e.IsActive);

you are actually calling methods with a different signature depending on the type of filteredCollection (It's Func<MyClass, bool> for IEnumerable and Expression<Func<MyClass, bool>> for IQueryable).

Regarding your specific situation, you can't achieve what you want to do directly, but if you write a sneaky extension method:

public static class ExpressionExtensions
{
    public static Expression<Func<T, TProperty>> Lambda<T, TProperty>(this ParameterExpression pe, Expression<Func<T, TProperty>> property)
    {
        return Expression.Lambda<Func<T, TProperty>>(property, pe);
    }
}

then you can do this:

var pe = Expression.Parameter(typeof(DateTime?));
var ex = pe.Lambda<DateTime?, bool>(x => x.HasValue);
于 2013-11-12T14:59:42.133 回答