如何从C#中的表达式中提取所有属性访问语句?

如何从C#中的表达式中提取所有属性访问语句?,c#,lambda,properties,expression,C#,Lambda,Properties,Expression,我已经为C#/WPF实现了一个命令条件机制,它可以自动驾驶,无论是否执行特定操作。为了解释问题的动机,这里有一个简单的例子 this.DocumentExistsCondition = new Condition(false); this.SaveDocumentCommand = new AppCommand(() => DoSaveDocument, DocumentExistsCondition); 然后我可以改变条件,如: this.DocumentExistsCondition

我已经为C#/WPF实现了一个命令条件机制,它可以自动驾驶,无论是否执行特定操作。为了解释问题的动机,这里有一个简单的例子

this.DocumentExistsCondition = new Condition(false);
this.SaveDocumentCommand = new AppCommand(() => DoSaveDocument, DocumentExistsCondition);
然后我可以改变条件,如:

this.DocumentExistsCondition.Value = false;
因此,所有相关命令都会更改其可用性。该机制很复杂,允许聚合条件,并对它们进行聚合和/或聚合等

其中一种条件类型允许用户指定成员的成员并查看其值,如:

documentExistsCondition = new MutablePropertyNotNullCondition<DocumentsManager, BaseDocumentViewModel>(documentsManager, dm => dm.ActiveDocument);
documentExistsCondition=new MutablePropertyNotNullCondition(documentsManager,dm=>dm.ActiveDocument);
这进一步简化了事情,因为我不再需要主动跟踪属性,这个条件实现为我做到了这一点

但我的机制非常有限,因为指定为第二个参数的表达式必须是属性访问语句。这是因为我正在提取属性名,检查源实例是否实现了INotifyPropertyChange,然后钩住这个特定属性的更改

我想扩展这个机制,允许用户提供对某个对象求值的任何表达式,但使用源代码中的单个属性,即

documentExistsCondition = new MutablePropertyNotNullCondition<DocumentsManager, BaseDocumentViewModel>(documentsManager, dm => dm.ActiveDocument != null ? dm.ActiveDocument : BaseDocumentViewModel.Default);
documentExistsCondition=new MutablePropertyNotNullCondition(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;
}
private PropertyInfo GetPropertyInfo(表达式propertyLambda)
{
类型类型=类型(TClass);
var member=propertyLambda.Body作为MemberExpression;
if(成员==null)
抛出新ArgumentException(string.Format(
表达式“{0}”引用的是方法,而不是属性,
propertyLambda.ToString());
var propInfo=member.member作为PropertyInfo;
if(propInfo==null)
抛出新ArgumentException(string.Format(
表达式“{0}”引用的是字段,而不是属性,
propertyLambda.ToString());
if(type!=propInfo.ReflectedType&&
!type.IsSubclassOf(propInfo.ReflectedType))
抛出新ArgumentException(string.Format(
表达式{0}引用的属性不是来自类型{1},
propertyLambda.ToString(),
类型);
返回propInfo;
}
有没有一种方法可以简单地从复杂语句中提取所有属性访问语句的列表?还是我必须递归地遍历所有类型的表达式并手动执行


换言之:我是否可以在某个常规级别上遍历语句树(如ChildStatements中的foreach var childStatement){…}?

您应该能够使用一个:

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
公共类成员ExpressionRecorder:ExpressionVisitor
{
公共列表成员表达式{get;}=new List();
受保护的重写表达式VisitMember(MemberExpression节点)
{
MemberExpressions.Add(节点);
返回base.VisitMember(节点);
}
}
...
var visitor=new MemberExpressionRecorder();
访问(某种表达);
//访问visitor.MemberExpressions

请注意,lambda表达式(即根据lambda语法创建的排序)不是,也不能包含语句。你所说的“子语句”到底是什么意思?@canton7,我表达得不正确,我的意思是,“X.Prop!=null?X.Prop:5”就是一个例子。表达式树将包括比较、三元运算符和两个成员访问。我的目标是自动处理整个表达式,只获取成员访问(然后处理)Aha。使用
ExpressionVisitor