Dinâmica expressão lógica de análise / avaliação em C # ou VB?
-
20-08-2019 - |
Pergunta
Qual é a melhor foi avaliar uma expressão como o seguinte:
(A e B) ou (A e C) ou (Not B e C)
ou
(A && B) || (A && C) || (! B && C)
No momento da execução, eu estava pensando em converter as expressões acima ao seguinte:
(Verdadeiro e falso) ou (verdadeiro e falso) ou (Não falso e verdadeiro)
ou
(True && False) || (True && False) || (! Falso && True)
Condições: 1) A expressão lógica não é conhecido até a execução. 2) O número variável e os seus valores não são conhecidos até a execução. 3) Os valores de variáveis ??não são nulos.
Eu sei que poderia criar um simples montar com uma classe e um método que eu gerar em tempo de execução com base nas entradas, mas há uma maneira melhor. Eu já fiz isso antes. Use um construtor de string para escrever o código, em seguida, chamar o compilador. Depois disso, você carregar o assembly e chamar o método.
Sugestões?
Graças.
Solução
Se você estiver usando NET3.5 em seguida, você pode analisar o texto e criar uma árvore sytax abstrata usando as classes de expressão. Em seguida, criar uma instância LambdaExpression adequado e compilá-lo em um delegado, que você pode então executar.
A construção de um construtor de árvore de analisador e sintaxe para esse tipo de bastante simples gramática é bastante um exercício interessante e irá executar um pouco mais rápido do que chamar o compilador (e de mais puro no meu ponto de vista também).
Se você não estiver usando NET3.5, então também não é complicado para implementar uma árvore de sintaxe abstrata si mesmo interpretado.
Outras dicas
Esteja avisado: as duas condições finais que você está falando não são necessariamente equivalentes. Os && operadores em C # irá utilizar evalution curto-circuito, enquanto o operador And
lógica em VB não. Se você quer ter certeza das declarações são equivalentes, traduzir um And
usuário AndAlso
e uma Or
usuário OrElse
.
Para expresssions simples que você provavelmente não vai notar a diferença. Mas se as condições podem ter efeitos colaterais ou se a diferença de desempenho entre os dois é uma preocupação, isso pode ser importante.
Você pode fazer isso facilmente com:
- um gerador de analisador (como ANTLR, mencionado acima) que leva expressões booleanas como entrada e produz uma lista infix e
- código para avaliar uma pilha Reverse Polish Notation.
A gramática é algo como isto:
program: exprList ;
exprList: expr { Append($1); }
| expr OR exprList { Append(OR); }
| expr AND exprList { Append(AND); }
| NOT exprList { Append(NOT); }
| ( exprList ) { /* Do nothing */ }
;
expr: var { Append($1); }
| TRUE { Append(True); }
| FALSE { Append(False); }
;
Para avaliar, você fazer isso:
for each item in list
if item is symbol or truth value, push onto RPN stack
else if item is AND, push (pop() AND pop())
else if item is OR, push (pop() OR pop())
else if item is NOT, push (NOT pop())
result = pop()
Para símbolos, você tem que substituir o valor de verdade em tempo de execução.
Você pode usar https://github.com/mrazekv/logicalparser
Seu simplesmente biblioteca para escrever expressão lógica (evaulated com mesa precenednce, permite OR, NOT, AND operador e>,> =, <=,
Você pode escrever um simples intérprete / parser. Use algo como ANTLR e reutilização gramáticas existentes.
Se você estiver usando o .NET 3.5, você pode criar uma expressão lambda. Em seguida, você pode criar um delegado dele e chamar como delegado / método padrão. Na internet é um monte de exemplos sobre expressões lambda.
Uma solução seria para montar a expressão como uma string e, em seguida, enviá-lo SQL Server, ou qualquer que seja o seu banco de dados é para avaliação. Substitua as variáveis ??reais com 1 = 1 ou 0 = 1 para verdadeiro e falso, respectivamente, e você iria acabar com uma consulta como esta:
SELECT 1 WHERE (1 = 1 e 0 = 1) ou (1 = 1 e 1 = 1) ou (Não 0 = 1 e 1 = 1)
Então, quando você executar a consulta, você começa a 1 de volta quando o resultado é verdadeiro. Pode não ser a solução mais elegante, mas vai funcionar. Muitas pessoas provavelmente irá aconselhar contra isso, mas eu só vou jogá-lo lá fora, como uma possível solução de qualquer maneira.
Esta não será a melhor resposta, mas eu mesmo tive esse problema há algum tempo.
Aqui está o meu código antigo: VB.Net - nenhuma garantia em tudo
https://cloud.downfight.de/index.php/s/w92i9Qq1Ia216XB
Dim BoolTermParseObjekt As New BoolTermParse
MsgBox(BoolTermParseObjekt.parseTerm("1 und (((0 oder 1 und (0 oder 4))) oder 2)").ToString)
Este código come uma string com múltiplas '(', ')', 'e', ??'ou' plus 'outras coisas' e quebra a lógica para um booleano, substituindo as coisas com valores booleanos. portanto:
Eu Quaisquer que sejam 'outras coisas' queria avaliar eu tive que colocar em resolveTerm Function () com o comentário "'Funktionen ausführen und zurückgeben, einzelwert!" na página 2. Há a única rightnow avaliação é "Se o número for> 1"
Greetings
Dê uma olhada em minha biblioteca, Proviant . É uma biblioteca .NET padrão usando o Manobras Quintal algoritmo para avaliar expressões booleanas.
Ele também poderia gerar uma tabela de verdade para as suas expressões.
Você também pode implementar sua própria gramática.