views:

50

answers:

2

I'm writing something in the flavour of Enumerable.Where in that takes a predicate of the form Func<T, bool>. If the underlying T implements INotifyPropertyChanged, I'd like to be a bit more intelligent about re-evaluating the predicate.

I'm thinking about changing it to use Expression<Func<T, bool>>, and then using the expression tree to find out which properties are used in the predicate. Then I can have my PropertyChanged handler be a bit more intelligent.

My question: is this feasible? If the predicate's simple (e.g. x => x.Age > 18), then the Expression seems to have everything I need in it. Are there scenarios where I won't be able to see which properties are referenced?

+2  A: 

Yes, you'll be able to see everything directly referenced. Of course, if someone passes

x => ComputeAge(x) > 18

then you won't necessarily know that ComputeAge refers to the Age property.

The expression tree will be an accurate representation of exactly what's in the lambda expression.

Jon Skeet
Cool, so if it's a simple expression, I'm good. If it's a complex expression, I'll have to fall back onto blindly re-evaluating the predicate.
Roger Lipscombe
@Roger: Even if it only contains properties, you need to consider whether those properties will refer to others. For example, suppose the `Age` property uses the `DateOfBirth` property... then a change to `DateOfBirth` should trigger re-evaluation, but the expression won't directly expose that dependency :(
Jon Skeet
Bah, so the answer (for my purposes) is "No: you can't reliably see which properties are used". Fair enough: blind re-evaluation is the solution then.
Roger Lipscombe
+1  A: 

Small code example of a visitor that would find directly referenced properties.

public class PropertyAccessFinder : ExpressionVisitor {
    private readonly HashSet<PropertyInfo> _properties = new HashSet<PropertyInfo>();

    public IEnumerable<PropertyInfo> Properties {
        get { return _properties; }
    }

    protected override Expression VisitMember(MemberExpression node) {
        var property = node.Member as PropertyInfo;
        if (property != null)
            _properties.Add(property);

        return base.VisitMember(node);
    }
}

// Usage:
var visitor = new PropertyAccessFinder();
visitor.Visit(predicate);
foreach(var prop in visitor.Properties)
    Console.WriteLine(prop.Name);
Simon Svensson