Как подписаться на событие объекта внутри дерева выражений? - PullRequest
1 голос
/ 20 декабря 2009

Извините, я не мог придумать лучшего названия. Это вопрос, состоящий из двух частей, который имеет смысл только вместе.

Скажем, у меня есть такой конструктор

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

}

и вот как это используется

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

, где AllowEditing является типом INotifyPropertyChanged

Я хотел бы изменить конструктор на

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

Так можно назвать вот так

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

Вопрос в том, как разобрать это выражение, чтобы «заметить» из дерева выражений, а затем подписаться на его событие?

Приведенный выше код не мой, он взят из недавнего примера из Ayende, вот как полный исходный код, если кто-то захочет взглянуть на то, как используется класс Fact *

1 Ответ

1 голос
/ 21 декабря 2009

В основном, объект, который вам нужен в этом случае, сохраняется в expression.Body.Expression. Вам нужно будет скомпилировать и выполнить дерево выражений, чтобы получить его. Кроме того, вам, вероятно, понадобится проверить, действительно ли тип реализует ваш интерфейс и является ли предикат тем, что вы действительно ищете.

Вот очень грубый код:

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()();
    //...
}
...