给出{/ 1}}
Expression<Func<TEntity, bool>>
我试图按类型提取列表属性条件,即
entity => entity.SubEntity.Any(
subEntity => (
(subEntity.SomeProperty == False)
AndAlso
subEntity.SubSubEntity.FooProperty.StartsWith(
value(SomeClass+<>c__DisplayClass0).ComparisonProperty
)
AndAlso
subEntity.SubSubEntity.BarProperty == "Bar"
AndAlso
subEntity.SubSubEntity.SubSubSubEntity.Any(
subSubSubEntity => (x.SubSubSubSubEntity.BazProperty == "whatever")
)
)
)
到目前为止,我创建了一个TEntity : [ /* no conditions for immediate members of TEntity */ ]
TSubEntity : [ { SomeProperty == False } ]
TSubSubEntity : [ { FooProperty.StartsWith(/* ... */) },
{ BarProperty == "Bar" } ],
TSubSubSubEntity : [ /* no conditions for immediate members of TSubSubSubEntity */ ],
TSubSubSubSubEntity : [ { BazProperty == "whatever" } ]
并将ExpressionVisitor
方法标识为我要插入的方法以获取我的信息。
我仍然感到茫然
VisitBinary
是否代表一个终结语句(从某种意义上说,我不需要查看更多嵌套表达式)BinaryExpression
关注的实体类型BinaryExpression
方法,以涵盖我尚未考虑过的案例。答案 0 :(得分:4)
不确定用例是什么,但这里有一些起点
class TestVisitor : ExpressionVisitor
{
public Dictionary<Type, List<Tuple<MemberExpression, Expression>>> Result = new Dictionary<Type, List<Tuple<MemberExpression, Expression>>>();
Stack<Expression> stack = new Stack<Expression>();
public override Expression Visit(Expression node)
{
stack.Push(node);
base.Visit(node);
stack.Pop();
return node;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression.NodeType != ExpressionType.Constant && (node.Type == typeof(string) || !typeof(IEnumerable).IsAssignableFrom(node.Type)))
{
var expression = stack.Skip(1).FirstOrDefault();
if (expression != null && expression.Type == typeof(bool))
{
List<Tuple<MemberExpression, Expression>> resultList;
if (!Result.TryGetValue(node.Expression.Type, out resultList))
Result.Add(node.Expression.Type, resultList = new List<Tuple<MemberExpression, Expression>>());
resultList.Add(Tuple.Create(node, expression));
}
}
return base.VisitMember(node);
}
}
这个想法很简单。覆盖Visit
方法只是为了维护一堆处理表达式。主要处理在VisitMember
覆盖内,为每个属性/字段访问者调用。 node.Expression.NodeType != ExpressionType.Constant
用于消除闭包成员,而第二个条件用于消除集合属性。最后,从堆栈中提取潜在条件表达式。
结果包括MemberExpression
和使用它的Expression
。 MemberExpression.Expression.Type
是您的实体类型,MemberExpression.Member
是该类型的属性/字段。
样品测试:
class Entity
{
public ICollection<SubEntity> SubEntity { get; set; }
}
class SubEntity
{
public bool SomeProperty { get; set; }
public SubSubEntity SubSubEntity { get; set; }
}
class SubSubEntity
{
public string FooProperty { get; set; }
public string BarProperty { get; set; }
public ICollection<SubSubSubEntity> SubSubSubEntity { get; set; }
}
class SubSubSubEntity
{
public SubSubSubSubEntity SubSubSubSubEntity { get; set; }
}
class SubSubSubSubEntity
{
public string BazProperty { get; set; }
}
class Program
{
static void Main(string[] args)
{
string comparisonProperty = "Ivan";
Expression<Func<Entity, bool>> e =
entity => entity.SubEntity.Any(subEntity =>
subEntity.SomeProperty == false
&&
subEntity.SubSubEntity.FooProperty.StartsWith(comparisonProperty)
&&
subEntity.SubSubEntity.BarProperty == "Bar"
&&
subEntity.SubSubEntity.SubSubSubEntity.Any(subSubSubEntity => subSubSubEntity.SubSubSubSubEntity.BazProperty == "whatever")
);
var v = new TestVisitor();
v.Visit(e);
var result = v.Result;
}
}