按类型从表达式中提取所有条件
Extract all conditions from Expression by Type
根据
给出一个 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
所关注的实体类型
- 我是否需要重写任何其他
ExpressionVisitor
方法来涵盖我尚未考虑的情况。
不确定真正的用例是什么,但这里是一些起点
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
覆盖内,每个 property/field 访问器都会调用它。 node.Expression.NodeType != ExpressionType.Constant
用于消除闭包成员,而第二个条件消除集合属性。最后从栈中提取出潜在的条件表达式。
结果包括 MemberExpression
和使用它的 Expression
。 MemberExpression.Expression.Type
是您的实体类型,MemberExpression.Member
是该类型的 property/field。
样本测试:
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;
}
}
根据
给出一个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
所关注的实体类型 - 我是否需要重写任何其他
ExpressionVisitor
方法来涵盖我尚未考虑的情况。
不确定真正的用例是什么,但这里是一些起点
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
覆盖内,每个 property/field 访问器都会调用它。 node.Expression.NodeType != ExpressionType.Constant
用于消除闭包成员,而第二个条件消除集合属性。最后从栈中提取出潜在的条件表达式。
结果包括 MemberExpression
和使用它的 Expression
。 MemberExpression.Expression.Type
是您的实体类型,MemberExpression.Member
是该类型的 property/field。
样本测试:
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;
}
}