views:

69

answers:

1

Sorry I couldn't think of a better title. This is a two part question that only make sense together.

Say I have a constructor like this

public Fact(INotifyPropertyChanged observable, Func<bool> predicate)
{
 this.predicate = predicate;
 observable.PropertyChanged += (sender, args) =>
                     PropertyChanged(this, new PropertyChangedEventArgs("Value"));

}

and this is how it's used

new Fact(Model.AllowEditing, () => Model.AllowEditing);

where AllowEditing is a type of INotifyPropertyChanged

I would like to refactor the constructor into

public Fact(Expression<Func<bool>> expression)

So it can be call like this

new Fact(() => Model.AllowEditing);

The question is how to parse that expression to get "observable" out of the expression tree then subscribe to its event?

The code above is not mine, it come from an example recent example from Ayende, here is the like to the full source code if anyone want to take a look of how the Fact class is being used http://github.com/ayende/Effectus

+1  A: 

Basically, the object you need in this case is stored in expression.Body.Expression. You will need to compile and execute an expression tree to get it. Also, you will probably need to check whether the type really implements your interface and whether the predicate is what your really are looking for.

Here is a very rough code:

public Fact(Expression<Func<bool>> predicate)
{        
    this.predicate = predicate;
    MemberExpression body = predicate.Body as MemberExpression;

    // Check that you get a valid lambda expression, 
    // like object.Member, not something like !object.Member
    if (body == null) 
         throw new ArgumentException("'" + predicate + "': is not a valid expression for this method");
    var type = body.Expression.Type;

    // Check if type implements INotifyPropertyChanged using reflection  
    // ...

    INotifyPropertyChanged observable = 
    Expression.Lambda<Func<INotifyPropertyChanged>>(body.Expression).Compile()();
    //...
}
Alexandra Rusina
the predicate doesn't come in as a MemberExpression, it's UnaryExpression. So I play around with it but still couldn't get to work.I like your EExpression.Lambda<Func<INotifyPropertyChanged>>(body.Expression).Compile()();That's some serious code to wrap my head around.
firefly
Hm... How can it be UnaryExpression? To get a unary expression, you need to supply a lambda expression with a unary operation. For example, !(Model.AllowEditing), -Model.AllowEditing or Model.AllowEditing++. But this is what I meant by "check whether the predicate is what you are really looking for". Basically, you want to accept only MemberExpression here, and if "body" is null you should just throw an exception like "InvalidArgument".As for Compile()(), just be aware that in fact it is a heavy operation. Don't overuse it.
Alexandra Rusina
I am not sure why, my knowledge in this area is still limited. Though that's what reported to me in the debugger.
firefly
Can you post the exact code where you call this constructor? I bet it looks like new Fact(() => !Model.AllowEditing);
Alexandra Rusina
Yes, I call it like thisnew Fact(() => Model.AllowEditing);However it's worth pointing out that AllowEditing is not bool, It come from a class wrapper class Obserable<T> so it's Obserable<bool>. The code for the class can be found here if you have time to take a look http://github.com/ayende/EffectusSorry I had been a little busy over the course few weeks. I really appreciate your help.
firefly
I'd say, just use an expression tree visualizer and see what is actually inside your expression and then figure out how to get the MemberExpression you need. VS 2010 has a built-in visualizer (http://blogs.msdn.com/csharpfaq/archive/2009/11/19/debugging-expression-trees-in-visual-studio-2010.aspx). For 2008, there is sample: http://msdn.microsoft.com/en-us/library/bb397975.aspx. The code you refer to is simply too long and hard for me to analyze at a glance.
Alexandra Rusina
Thanks to your pointer I figure it out :). Sorry I had been extremely busy for the past few month.
firefly