Как извлечь все операторы доступа к свойствам из выражения в C#? - PullRequest
0 голосов
/ 18 июня 2020

Я реализовал механизм "команда-условие" для C # / WPF, который автоматизирует движение, независимо от того, может ли быть выполнено определенное действие c или нет. Просто для объяснения мотивов вопроса, вот простой пример.

this.DocumentExistsCondition = new Condition(false);
this.SaveDocumentCommand = new AppCommand(() => DoSaveDocument, DocumentExistsCondition);

Тогда я могу просто изменить условие, например:

this.DocumentExistsCondition.Value = false;

Чтобы все зависимые команды изменили свою доступность . Механизм сложный, позволяет агрегировать условия, а также задавать их и вводить и т. Д. c.

Один из типов условий позволяет пользователю указать член-член и посмотреть его значение, например:

documentExistsCondition = new MutablePropertyNotNullCondition<DocumentsManager, BaseDocumentViewModel>(documentsManager, dm => dm.ActiveDocument);

Это еще больше упрощает ситуацию, поскольку мне больше не нужно активно отслеживать свойство, эта реализация условия делает это за меня.

Мой механизм довольно ограничен, потому что выражение, указанное как второй параметр должен быть оператором доступа к свойству. Это потому, что я извлекаю имя свойства, проверяю, реализует ли исходный экземпляр INotifyPropertyChange, а затем перехватываю для этого изменения c свойства.

Я хотел бы расширить этот механизм и разрешить пользователю предоставлять любые выражения, которые оценивают к какому-то объекту, но используйте единственное свойство из источника, ie.

documentExistsCondition = new MutablePropertyNotNullCondition<DocumentsManager, BaseDocumentViewModel>(documentsManager, dm => dm.ActiveDocument != null ? dm.ActiveDocument : BaseDocumentViewModel.Default);

В настоящее время я извлекаю свойство следующим образом:

private PropertyInfo GetPropertyInfo<TClass, TClassProperty>(Expression<Func<TClass, TClassProperty>> propertyLambda)
{
    Type type = typeof(TClass);

    var member = propertyLambda.Body as MemberExpression;
    if (member == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a method, not a property.",
            propertyLambda.ToString()));

    var propInfo = member.Member as PropertyInfo;
    if (propInfo == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a field, not a property.",
            propertyLambda.ToString()));

    if (type != propInfo.ReflectedType &&
        !type.IsSubclassOf(propInfo.ReflectedType))
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a property that is not from type {1}.",
            propertyLambda.ToString(),
            type));

    return propInfo;
}

Есть ли способ просто извлечь список всех операторов доступа к свойствам из сложного оператора? Или мне нужно go рекурсивно перебирать все виды выражений и делать это вручную?

Другими словами: могу ли я пройти по дереву операторов на каком-то общем уровне (например, foreach var childStatement in ChildStatements) { ... })?

1 Ответ

1 голос
/ 18 июня 2020

Вы должны иметь возможность использовать ExpressionVisitor для этого:

public class MemberExpressionRecorder : ExpressionVisitor
{
    public List<MemberExpression> MemberExpressions { get; } = new List<MemberExpression>();

    protected override Expression VisitMember(MemberExpression node)
    {
        MemberExpressions.Add(node);
        return base.VisitMember(node);
    }
}

...

var visitor = new MemberExpressionRecorder();
visitor.Visit(someExpression);
// access visitor.MemberExpressions
...