PDF de programación - Cómo evaluar expresiones matemáticas en VB .Net

Imágen de pdf Cómo evaluar expresiones matemáticas en VB .Net

Cómo evaluar expresiones matemáticas en VB .Netgráfica de visualizaciones

Actualizado el 21 de Marzo del 2018 (Publicado el 11 de Febrero del 2018)
947 visualizaciones desde el 11 de Febrero del 2018
77,7 KB
8 paginas
Creado hace 14a (20/07/2009)
Cómo evaluar expresiones matemáticas en
VB .Net

Por José G. Alvarez

Contenido

Introducción
La clase Evaluador
El método PrecompilarAssembly
El método Evaluar
Implementado Evaluador
Conclusión
Referencias

Introducción
Generalmente denominamos funciones, a las expresiones matemáticas o no, posibles de ser
evaluadas. Sin embargo, para simplificar este artículo, las llamaremos sencillamente "expresiones",
para no confundirlas con el concepto de función en los lenguajes de programación.
En algunas ocasiones nos encontramos con la imposibilidad de evaluar directamente una expresión
en VB .Net. Y es que desde los inicios del Basic, nunca ha existido una función propia del lenguaje
que evalúe una expresión.
Recuerdo con nostalgia cuando, con GWBasic, aprendí un artilugio que consistía en que nuestro
código creara un archivo secuencial (con extensión .bas) que contuviera el código de una función, y
dentro de esta función escribiéramos la expresión que queríamos evaluar. Claro, esto era posible
pues GW era un lenguaje interpretado y no existía un compilador que generara un ejecutable.
En VB el truco consistía en usar una referencia a un objeto Microsoft Script Control y usar su
método Eval. Como se muestra en el ejemplo siguiente:
Dim oSC As New ScriptControl
Dim expMath As String
Dim expToEval As String
oSC.Language = "VBScript"
expMath = "X ^ 2 + 2 * X + 1"
expToEval = Replace(expMath, "X", 5)
MsgBox oSC.Eval(expToEval)

Esta técnica, aunque resulta muy útil y en algunos casos soluciona nuestros problemas, está limitada
a que sólo podemos usar objetos y/o funciones definidas por VBScript dentro del parámetro

Expression del método Eval.
Todo esto ha servido para que reflexione sobre cuán viejo soy, aunque éstas no son las técnicas de
reflexión que se usan en VS .Net. De éstas vamos a hablar más adelante.
Si bien en VB .Net podemos hacer referencia a un objeto Microsoft Script Control, tendríamos las
mismas desventajas que con versiones anteriores de VB. ¿Cómo podemos entonces evaluar una
expresión en VB .Net, sin desaprovechar las bondades de .Net? Si recordamos el artilugio que se
usaba con GWBasic, lo desempolvamos y lo implementamos bajo la plataforma .Net, podremos no
solo evaluar una expresión, si no crear y ejecutar cualquier código de forma dinámica. Sin embargo,
por ahora nos conformaremos con crear una clase que evalúe una expresión matemática.
Crearemos entonces una clase Evaluador. Esta creará un assembly con el código que deseamos
ejecutar, en este caso un método o función con la expresión a evaluar. Luego, usando la reflexión
invocará este método y obtendremos los resultados. Suena sencillo… ¡Realmente lo es!

La clase Evaluador
La clase Evaluador contendrá un objeto privado (oEnsamblado) de tipo assembly (del espacio de
nombres System.Reflection) y dos métodos públicos: PrecompilarAssembly y Evaluar. He
decidido separar ambos métodos por cuestiones de rendimiento. Si combináramos los dos métodos
y fuésemos a dibujar la grafica de una expresión, el rendimiento final sería simplemente
inaceptable. La compilación de un assembly requiere una cantidad de proceso considerable.
El objeto oEnsamblado será la representación del assembly que compilaremos. Este assembly,
como mencionamos anteriormente, será una clase (EvalClase) que expondrá un único método
(Eval) que contendrá la expresión a evaluar y retornará el resultado:
Imports System.Text
Imports System.CodeDom.Compiler
Imports System.Collections.Specialized
Public Class Evaluador
Private oEnsamblado As System.Reflection.Assembly
Public Sub PrecompilarAssembly ...
End Sub Public Function Evaluar ..
End Sub

El método PrecompilarAssembly
El método PrecompilarAssembly, como su nombre lo indica, precompila el assembly de la clase
que contiene un método con la expresión a evaluar. Vamos a visualizar el código a generar y los
posibles escenarios dependientes de la expresiones a evaluar.
Supongamos que deseamos evaluar la expresión matemática y(x) = x + 3. El código necesario sería
algo así como lo que se muestra a continuación:
Public Class EvalClase

Public Shared Function Eval(ByVal X As Double) as Object
Return X + 3
End Function
End Class

Por otro lado, supongamos que queremos evaluar z(x,y) = Log(x) + y:
Imports System.Math

Public Class EvalClase
Public Shared Function Eval(ByVal X As Double, ByVal Y As
Double) as Object
Return Log10(X) + Y
End Function
End Class

Vemos que existen tres factores cambiantes: la expresión, los parámetros del método Eval y los
namespaces. Por lo tanto nuestro método Precompilarfuncion recibirá tres parámetros,
correspondientes a esos elementos. Veamos entonces el método PrecompilarAssembly:
Public Function PrecompilarAssembly(ByVal Funcion As String, _
ByVal ParametrosList As StringCollection, ByVal NameSpaceList As
StringCollection) As Boolean

Dim mStrings As String
Dim mParametros As String
'Definimos un objeto de tipo StringBuilder que contendra el
código a compilar
Dim CodigoFuente As New StringBuilder()

'Agregamos los Imports necesarios a nuestro codigo fuente
For Each mStrings In NameSpaceList
CodigoFuente.Append("Imports " & mStrings & vbCr)

Next

'Preparamos un string con los parametros que usará el metodo Eval
'de de la clase EvalClase
For Each mStrings In ParametrosList
mParametros &= ", " & mStrings
Next

mParametros = Trim(mParametros)
If mParametros.Length > 0 Then
mParametros = Trim(Mid(mParametros, 2))
End If

'Terminamos de construir la clase a compilar
CodigoFuente.Append("Public Class EvalClase" & vbCr)
CodigoFuente.Append(" Public Shared Function Eval(" & _
mParametros & ") as Object" & vbCr)
CodigoFuente.Append(" Return " & Funcion & vbCr)
CodigoFuente.Append(" End Function " & vbCr)
CodigoFuente.Append("End Class " & vbCr)

'Creamos una instancia de la clase VBCodeProvider
'que usaremos para obtener una referencia a una interfaz
ICodeCompiler
Dim oCProvider As New VBCodeProvider()
Dim oCompiler As ICodeCompiler = oCProvider.CreateCompiler


'Usamos la clase CompilerParameters para pasar parámetros al
compilador
'En particular, definimos que el assembly sea compilado en
memoria.
Dim oCParam As New CompilerParameters()
oCParam.GenerateInMemory = True

'Creamos un objeto CompilerResult que obtendrá los resultados de
la compilación
Dim oCResult As CompilerResults
oCResult = oCompiler.CompileAssemblyFromSource(oCParam,
CodigoFuente.ToString)

'Comprobamos que no existan errores de compilación.
Dim oCError As CompilerError
If oCResult.Errors.Count > 0 Then
'Si existen errores los mostramos.
'Si bien, podriamos implementar un mejor método para
visualizar
'los errores de compilación, este nos servirá por los
momentos.
For Each oCError In oCResult.Errors
MsgBox(oCError.ErrorText.ToString)
Next
Return False
Else
'Como el ensamblado se generó en memoria, debemos obtener
'una referencia al ensamblado generado, para esto usamos

'la propiedad CompiledAssembly
oEnsamblado = oCResult.CompiledAssembly
Return True
End If
End Sub

El método PrecompilarAssembly devolverá True o False dependiendo de si la compilación tuvo
éxito o no. El assembly compilado en memoria, estará referenciado por el objeto oEnsamblado.

El método Evaluar
Ahora necesitamos invocar el método Eval de nuestro assembly recientemente generado. Para ello,
haremos uso de las técnicas de reflexión:
Public Function Evaluar(ByVal ParamArray Parametros() As Object)
As Object
If oEnsamblado Is Nothing Then
Return Nothing
Else
'Instanciamos la clase EvalClase de nuestro assembly
'creando un tipo a partir de ella.
Dim oClass As Type = oEnsamblado.GetType("EvalClase")

'Usamos GetMethod para accesar al método Eval, e invocamos este
con los parametros necesarios.
Return oClass.GetMethod("Eval").Invoke(Nothing,
Parametros)
End If
End Function

Implementado Evaluador
Veamos ahora cómo usar nuestra clase Evaluador. En el ejemplo se evaluara la expresión z(x,y) =
Log(x) + y; con x = 100, y=3.
Nota: recuerda que en notación matemática, Log(x) simboliza el logaritmo de x en base 10; luego,
debemos usar la función Log10.
'Creamos una nueva instancia de la clase Evaluador

Dim mEval As New Evaluador.Evaluador()

'Creamnos una variable tipo string y le asignamos la expresión
que queremos evaluar
Dim mExpresion As String = "Log10(X) + Y"

'Creamos un objeto StringCollection y agregamos los parámetros de
entrada que usará el método eval
Dim mParameters As New StringCollection()
mParameters.Add("ByVal X as Double")
mParameters.Add("ByVal Y as Double")

'En este caso, la función Log10() Pertenece al espacio de nombres
System.Math.
'se hace necesario entonces, crear un objeto StringCollection y
agregar
'el namespace System.Math.
Dim mNameSpaces As New StringCollection()
mNameSpaces.Add("System.Math")

'Invocamos el método PrecompilarFunción y verificamos si se
genero correctamente el assembly.
If If mEval.PrecompilarFuncion(mExpresion, mParameters,
mNameSpaces) Then
'Si el assembly se generó correctamente, creamos un array con
los valores de los parametros a evaluar
Dim mParam() = {100, 3}
'invocamos el método Evaluar y mostramos el resultado

MsgBox(mEval.Evaluar(mParam))
Else
MsgBox("No se ha generado el Assembly")
End If

Conclusión
Hemos utilizado las técnicas de compilar mediante código para crear un assembly en memoria y
luego, mediante la reflexión, invocar sus métodos. Se me ocurren en este momento no menos de 10
mejoras que se pueden hacer a la clase Evaluador. Sin embargo, la he construido con un propósito
específico: crear una clase Graficador que implementará la clase Ev
  • Links de descarga
http://lwp-l.com/pdf8726

Comentarios de: Cómo evaluar expresiones matemáticas en VB .Net (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios...
CerrarCerrar
CerrarCerrar
Cerrar

Tienes que ser un usuario registrado para poder insertar imágenes, archivos y/o videos.

Puedes registrarte o validarte desde aquí.

Codigo
Negrita
Subrayado
Tachado
Cursiva
Insertar enlace
Imagen externa
Emoticon
Tabular
Centrar
Titulo
Linea
Disminuir
Aumentar
Vista preliminar
sonreir
dientes
lengua
guiño
enfadado
confundido
llorar
avergonzado
sorprendido
triste
sol
estrella
jarra
camara
taza de cafe
email
beso
bombilla
amor
mal
bien
Es necesario revisar y aceptar las políticas de privacidad