C#表达式访问者,如何否定构建过滤器
作者:互联网
我为第三方api构建自己的IQuerable实现.
此Api接受过滤器作为OR的列表,其中包含AND语句和fitlers列表,如下所示:
public class Or {
List<And> ands
}
public class And {
field, operator, value..
}
Filters = new List<Or>();
现在建立这些过滤器很好,每当我有一个或声明我爆炸所有当前的过滤器或当我得到和声明我添加到所有的或.这些似乎工作得很好,除非现在每当我有一个一元不在多个领域的表达,我迷路了.
说我有:(a和b)或(c和d)
这会变成过滤器:
a, b // list of ands, vertical list of or
c, d
否定这将导致:(!a或!b)和(!c或!d)
!a, !c
!a, !d
!b, !c
!b, !d
这仍然是可能的,但我想弄清楚的是,如果它会被双重否定,我将如何能够恢复它,这将再次导致(a和b)或(c和d).但我似乎无法弄明白.也许我应该使用不同的中间过滤器结构,然后将它们转换为这些和/或列表.我怎么能做到这一点?
解决方法:
当您反转示例时,它会变成一个更大的列表,正如您所指出的:
!((a & b) | (c & d))
!(a & b) & !(c & d) // De Morgan's laws
(!a | !b) & (!c | !d) // De Morgan's laws
(!a & !c) | (!a & !d) | (!b & !c) | (!b & !d) // Normalization
再次反转时,列表会变得更大:
!((!a & !c) | (!a & !d) | (!b & !c) | (!b & !d))
!(!a & !c) & !(!a & !d) & !(!b & !c) & !(!b & !d) // De Morgan's laws
(!!a | !!c) & (!!a | !!d) & (!!b | !!c) & (!!b | !!d) // De Morgan's laws
(a | c) & (a | d) & (b | c) & (b | d) // Double negation
(a & a & b & b) | (a & a & b & d) | (a & a & c & b) | (a & a & c & d) | (a & d & b & b) | (a & d & b & d) | (a & d & c & b) | (a & d & c & d) | (c & a & b & b) | (c & a & b & d) | (c & a & c & b) | (c & a & c & d) | (c & d & b & b) | (c & d & b & d) | (c & d & c & b) | (c & d & c & d) // Normalization
哇,最后一行确定很长!你会注意到一些联合条款有重复,即& amp; a& b&湾因此,第一步是删除重复的谓词:
(a & b) | (a & b & d) | (a & c & b) | (a & c & d) | (a & d & b) | (a & d & b) | (a & d & c & b) | (a & d & c) | (c & a & b) | (c & a & b & d) | (c & a & b) | (c & a & d) | (c & d & b) | (c & d & b) | (c & d & b) | (c & d)
现在我们可以在每个连词中排序谓词,并删除重复的连词:
(a & b) | (a & b & c) | (a & b & c & d) | (a & b & d) | (a & c & d) | (b & c & d) | (c & d)
好的,这清理了很多!但是,我们在这个表达方面仍然比我们开始时有更多.如果仔细观察,其中一些连词是多余的 – 例如a& b& c => a&湾所以,如果一个连词是另一个连词的超集,我们可以删除它:
(a & b) | (c & d)
原条款!由于您的问题中未包含任何代码,因此我不会在答案中包含任何代码 – 执行上述步骤取决于您.但是,我建议你简化你的模型:
public class Predicate
{
public string Field { get; set; }
public Operator Operator { get; set; }
public string Value { get; set; }
}
public enum NormalForm
{
Conjunctive,
Disjunctive
}
public class Filter
{
public NormalForm NormalForm { get; set; }
public List<List<Predicate>> Predicates { get; set; }
}
这是一种更灵活的表示,并且会使反转变得更容易,因为在你应用了De Morgan的定律之后,你最终会得到联合正规形式并且必须转换回来.
标签:c,expression,expressionvisitor 来源: https://codeday.me/bug/20190627/1304615.html