c# - studio - evaluar expresiones matematicas en visual basic
La mejor y más corta forma de evaluar expresiones matemáticas (6)
Hay muchos algoritmos para evaluar expresiones, por ejemplo:
¿Hay alguna manera de evaluar cualquier expresión matemática usando la reflexión C # .net u otra tecnología .NET moderna?
Ciertamente es posible. La clase CodeSnippetCompileUnit básicamente hace esto. Te escribí un ejemplo de código de uso. Deberá incluir estos espacios de nombres:
- System.CodeDom.Compiler;
- System.CodeDom;
- Microsoft.CSharp;
- System.Reflection;
Aquí está el código:
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 });
Reemplace ''parámetros'' y ''expresión'' por lo que sea, y obtendrá un evaluador de expresiones generales.
Si obtiene una excepción FileNotFoundException en results.CompiledAssembly, el fragmento no pudo compilarse.
También es posible que desee echar un vistazo a la clase System.CodeDom.CodeSnippetExpression. Se usa para leer expresiones más específicamente, pero una expresión en sí misma no se puede compilar, por lo que necesitaría usar más CodeDom para construir una clase trabajadora y un método a su alrededor. Esto es útil si desea poder manipular mediante programación qué tipo de clase está generando. CodeSnippetCompileUnit es agradable para generar una clase trabajadora completa a la vez (y más simple para un ejemplo), pero para manipularla tendrías que hacer manipulaciones de cadenas inconvenientes.
Para mí, Vici.Parser funciona muy bien: compruébalo aquí , es el analizador de expresiones más flexible que he encontrado hasta ahora.
(Lo hemos usado para configurar reglas comerciales ''legibles por humanos'', con datos proporcionados por una base de datos de servidor SQL)
Hay ejemplos disponibles y hay un muy buen soporte por parte del desarrollador (consulte el foro del sitio web).
Si bien el uso de servicios de compilación es una solución simple y eficiente, plantea serios problemas de seguridad si un usuario ingresa la expresión, ya que podría ejecutar virtualmente cualquier cosa .
Hay otra solución muy simple que es mucho más segura: aproveche la función JScript Eval
. Solo necesita seguir estos pasos:
Cree un archivo js llamado JsMath.js:
class JsMath
{
static function Eval(expression : String) : double
{
return eval(expression);
};
}
Compilarlo en una biblioteca de clase:
jsc /t:library JsMath.js
Haga referencia a la biblioteca JsMath en su proyecto C # y úselo de esta manera:
double result = JsMath.Eval(expression);
Además de la respuesta de Thomas, en realidad es posible acceder a las bibliotecas JScript (obsoletas) directamente desde C #, lo que significa que puede usar el equivalente de la función de eval
de 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();
Creo que esta es la mejor manera de todas. La respuesta de Petar Repac es increíble. El uso del argumento ''expresión'' del objeto DataColumn resuelve increíble y fácilmente el tema:
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"]);
}