Domanda

Esistono molti algoritmi per valutare le espressioni, ad esempio:

  1. Per discesa ricorsiva
  2. Algoritmo di shunting yard
  3. Notazione polacca inversa

Esiste un modo per valutare qualsiasi espressione matematica usando la riflessione C # .net o altre moderne tecnologie .net?

È stato utile?

Soluzione

Oltre alla risposta di Thomas, in realtà è possibile accedere alle librerie (obsolete) di JScript direttamente da C #, il che significa che è possibile utilizzare l'equivalente della funzione eval di JScript.

using Microsoft.JScript;        // needs a reference to Microsoft.JScript.dll
using Microsoft.JScript.Vsa;    // needs a reference to Microsoft.Vsa.dll

// ...

string expr = "7 + (5 * 4)";
Console.WriteLine(JScriptEval(expr));    // displays 27

// ...

public static double JScriptEval(string expr)
{
    // error checking etc removed for brevity
    return double.Parse(Eval.JScriptEvaluate(expr, _engine).ToString());
}

private static readonly VsaEngine _engine = VsaEngine.CreateEngine();

Altri suggerimenti

È certamente possibile. La classe CodeSnippetCompileUnit fa sostanzialmente questo. Ti ho scritto un esempio di codice di utilizzo. Dovrai includere questi spazi dei nomi:

  • System.CodeDom.Compiler;
  • System.CodeDom;
  • Microsoft.CSharp;
  • System.Reflection;

Ecco il codice:

string source = @"
class MyType
{
    public static int Evaluate(<!parameters!>)
    {
        return <!expression!>;
    }
}
";

string parameters = "int a, int b, int c";
string expression = "a + b * c";

string finalSource = source.Replace("<!parameters!>", parameters).Replace("<!expression!>", expression);

CodeSnippetCompileUnit compileUnit = new CodeSnippetCompileUnit(finalSource);
CodeDomProvider provider = new CSharpCodeProvider();

CompilerParameters parameters = new CompilerParameters();

CompilerResults results = provider.CompileAssemblyFromDom(parameters, compileUnit);

Type type = results.CompiledAssembly.GetType("MyType");
MethodInfo method = type.GetMethod("Evaluate");

// The first parameter is the instance to invoke the method on. Because our Evaluate method is static, we pass null.
int result = (int)method.Invoke(null, new object[] { 4, -3, 2 });

Sostituisci 'parametri' ed 'espressione' con qualunque cosa, e avrai un valutatore di espressioni generali.

Se si ottiene FileNotFoundException nei risultati.CompiledAssembly, la compilazione dello snippet non è riuscita.

Potresti anche dare un'occhiata alla classe System.CodeDom.CodeSnippetExpression. Viene utilizzato per la lettura più specifica delle espressioni, ma un'espressione da sola non può essere compilata, quindi è necessario utilizzare più CodeDom per creare una classe lavoratrice e un metodo attorno ad essa. Questo è utile se vuoi essere in grado di manipolare programmaticamente il tipo di classe che stai generando. CodeSnippetCompileUnit è bello generare un'intera classe lavoratrice in una volta (e più semplice per un esempio) ma per manipolarla dovresti fare manipolazioni di stringhe scomode.

Sebbene l'utilizzo dei servizi di compilazione sia una soluzione semplice ed efficiente, solleva seri problemi di sicurezza se l'espressione viene immessa da un utente, poiché potrebbe eseguire praticamente qualsiasi cosa .

C'è un'altra soluzione molto semplice che è molto più sicura: sfruttare la funzione JScript Eval . Devi solo seguire questi passaggi:

Crea un file js chiamato JsMath.js:

class JsMath
{
    static function Eval(expression : String) : double
    {
        return eval(expression);
    };
}

Compilalo in una libreria di classi:

jsc /t:library JsMath.js

Fai riferimento alla libreria JsMath nel tuo progetto C # e usala in questo modo:

double result = JsMath.Eval(expression);

Per me Vici.Parser funziona molto bene: controlla qui , è il parser di espressioni più flessibile che ho trovato finora.

(l'abbiamo usato per impostare regole aziendali "leggibili dall'uomo", con i dati forniti da un database del server SQL)

Sono disponibili esempi e c'è un ottimo supporto da parte dello sviluppatore (controlla il forum del sito Web).

ncalc è il migliore. puoi trovarlo in codeplex anche in nugget.
NCalc è un valutatore di espressioni matematiche in .NET. NCalc può analizzare qualsiasi espressione e valutare il risultato, inclusi parametri statici o dinamici e funzioni personalizzate.

Penso che questo sia il modo migliore di tutti. La la risposta di Petar Repac è sorprendente. L'uso dell'argomento 'espressione' dell'oggetto DataColumn risolve in modo incredibile e semplice l'argomento:

static double Evaluate(string expression)
{
    var loDataTable = new DataTable();
    var loDataColumn = new DataColumn("Eval", typeof(double), expression);
    loDataTable.Columns.Add(loDataColumn);
    loDataTable.Rows.Add(0);
    return (double)(loDataTable.Rows[0]["Eval"]);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top