Execute condition (if / else) that is inside a string in C # 4.5 [duplicate]

3

I have a class that generates csv files from a query, and this file can have multiple templates , some with conditions to display value x or y .

These conditions are within a database and when I retrieve this data the expression comes within a string . I used Reflection to do this and it worked, but it did a lot of application performance, considering that there are many lines.

I would like to know if there is any other way to execute an expression of if that is within a string .

Example of if :

string Exp = "A == B ? 123 : 345"

Here is the function I did:

string source = @"
    namespace cond
    {
        public class Bar
        {
            public string resultadoexpressao()
            {
                return "+expressao+";
            }
        }
    }";

Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
        {"CompilerVersion", "v3.5"}
};

CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);

CompilerParameters compilerParams = new CompilerParameters
{
    GenerateInMemory = false,
    GenerateExecutable = false
};

CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);

object o = results.CompiledAssembly.CreateInstance("cond.Bar");

MethodInfo mi = o.GetType().GetMethod("resultadoexpressao");

string resultado = (string)mi.Invoke(o, null);   

return resultado;
    
asked by anonymous 29.09.2017 / 22:18

2 answers

0

If you have the time, and you feel like learning something cool, you can create a very expression parser for this.

A good recipe to follow in a parser is to create the reading methods like this:

DadoDeRetorno LerAlgumaCoida(string codigo, ref int pos)
{
    // lê algo do código e avança a posição de leitura
}

This DadoDeRetorno depends on what you want to do.

  • interpret: in this case the output of most methods is the result of the interpretation. Since you will not know the type to be returned beforehand, then it will be object same.

  • generate syntax tree: in this case the output will be a syntactic tree node. This is the case, for example, of wanting to use Expression Trees, from LINQ, which you can then compile, which will give you a lot of performance gain.

  • compile: Few languages can be compiled directly from code, but an expression parser is probably an exception. In this case, you will probably want to return a string / array already with the translation to the target language.

For every thing that is successfully handled, you should update the pos variable. In addition, the return of each function should indicate whether or not the method succeeded to make things easier.

You will need methods like this template to read spaces, to read variable names, to read numbers, among others:

bool LerEspacos(string codigo, ref int pos); // retorna false se não ler nada
string LerNomeDeVariavel(string codigo, ref int pos); // retorna null se não ler nada
int? LerNumeroInteiro(string codigo, ref int pos); // retorna null se não ler nada

Each one can also receive other values relevant to each type of parser. For example, when making an interpreter, you must pass the values of the variables. If it's a compiler, you might need to pass a list of the registers in use and maybe even change that list.

You will also need a method to process the expressions. This goes into the same model, but within it, the implementation is a bit more complicated.

Expression LerExpressao(string codigo, ref int pos, Contexto contexto);

In this case you need two stacks, one for operators, and one for operands.

Whenever an operand is found, you stack it in the list of operands.

When an operator is found, you need to stack it on the operator stack, but only if it has higher precedence than the one already on the stack. Otherwise, it is necessary to perform the operation on the stack with the operands that are in the operand stack.

Example of the steps of an interpreter with two cells:

Entrada: 1 + 3 * 5 + 8

// Lê 1 da entrada e põe na pilha de operandos
Operandos: 1
Operadores: 

Entrada: + 3 * 5 + 8

// Lê "+" da entrada e põe na pilha de operadores
Operandos: 1
Operadores: +

Entrada: 3 * 5 + 8

// Lê 3 da entrada e põe na pilha de operandos
Operandos: 1 3
Operadores: +

Entrada: * 5 + 8

// Lê "*" da entrada e põe na pilha de operadores
Operandos: 1 3
Operadores: + *

Entrada: 5 + 8

// Lê 5 da entrada e põe na pilha de operandos
Operandos: 1 3 5
Operadores: + *

Entrada: + 8

// Não pode empilhar + sobre *
// Executa a operação 3 * 5 = 15
// Remove o operador * da pilha
// Remove os operandos 3 e 5 da pilha
// Adiciona o 15 e o + nas respectivas pilhas
Operandos: 1 15
Operadores: + +

Entrada: 8

Operandos: 1 15 8
Operadores: + +

// Acabou, agora basta ir executando todos os itens das pilhas
// 15 + 8 = 23

Operandos: 1 23
Operadores: +

// 1 + 23 = 24

Operandos: 24
Operadores:

// o resultado é o que sobra na pilha de operandos = 24
    
30.09.2017 / 00:11
0

If the expression is saved in the database, you can change it to the SQL itself to run the if/else , in case, if it is SQL Server, change the condition to a case , generate the query dynamically, loading the data from the parameterized tables and execute it with sp_sqlexec and return the value already treated 123 or 345 .

    
29.09.2017 / 23:09