2009-12-20 2 views
1

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

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

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, вот как на полный исходный код, если кто-то хочет посмотреть, как используется класс Факт http://github.com/ayende/Effectus

ответ

1

В принципе, объект, который вам нужен в этом случае, хранится в выражении.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()(); 
    //... 
} 
+0

предикат не приходит как MemberExpression, это УнарноеВыражение. Поэтому я играю с ним, но все равно не могу работать. Мне нравится ваше EExpression.Lambda > (body.Expression) .Compile()(); Это какой-то серьезный код для обертывания моей головы. – firefly

+0

Хм ... Как это может быть UnaryExpression? Чтобы получить унарное выражение, вам нужно предоставить лямбда-выражение с унарной операцией. Например,! (Model.AllowEditing), -Model.AllowEditing или Model.AllowEditing ++. Но это то, что я имел в виду под «проверить, является ли предикат тем, что вы действительно ищете». В принципе, вы хотите принять здесь только MemberExpression, и если «body» имеет значение null, вы должны просто выбросить исключение, например «InvalidArgument». Что касается Compile()(), просто имейте в виду, что на самом деле это тяжелая операция. Не злоупотребляйте им. –

+0

Я не знаю, почему, мои знания в этой области все еще ограничены. Хотя это то, что мне сообщили в отладчике. – firefly