2012-03-23 8 views
7

Tengo una cita donde leo la lógica de negocios y reemplazo las variables con valores reales y luego tengo que evaluarlo para obtener un resultado. Actualmente estoy usando bcParser para hacerlo y funciona muy bien para toda la lógica que se escribe como formato de Excel.¿Es posible crear un árbol de expresiones para sentencias if dinámicas?

La bola curva que se arroja sobre mí es que, la condición if no será como excel if(cond, true, false) sino que será como C# donde if (cond) { true; } else { false;}, esto tiene más sentido y es fácil de mantener. Como reemplazo todas las variables con valor de antemano, todo lo que tengo que hacer es evaluarlo. Actualmente estoy resolviendo este problema exportando la lógica a los métodos de C# y usando la reflexión lo estoy evaluando y también funciona.

Me pregunto si hay alguna otra opción, no quiero escribir código para cada condición if y me gustaría evaluarlo en el tiempo de ejecución. Me preguntaba si debería poder crear un analizador de tokens de algún tipo y llamar a la evaluación de expresión nativa de C# y realizar el cálculo. No he ido a la comprensión de los árboles de expresión, parece que es posible con ese enfoque. antes de ir allí, me gustaría saber si es posible en absoluto? Gracias,

+3

Los árboles de expresiones no te ayudarán a analizar la cadena. Es posible que desee consultar [CodeDom] (http://msdn.microsoft.com/en-us/library/y2k85ax6.aspx) o [Rosalyn] (http://msdn.microsoft.com/en-us/roslyn).) –

Respuesta

5

Sí!

La clave está utilizando el espacio de nombres System.Linq.Expressions. Puede construir un árbol de expresiones mediante programación, ya sea en su código o modificando su analizador y luego compilarlo en un Delegate. Esta API compila su Delegate dentro de un DynamicAssembly, lo que significa que el recolector de elementos no utilizados puede descargar sus expresiones compiladas cuando las elimina por completo.

Aquí es un ejemplo muy sencillo:

var b = true; 
Func<bool> condition =() => b; 
Action trueExpression =() => { Console.WriteLine(true); }; 
Action falseExpression =() => { Console.WriteLine(false); }; 

var e = Expression.Condition(
    Expression.Invoke(Expression.Constant(condition)), 
    Expression.Invoke(Expression.Constant(trueExpression)), 
    Expression.Invoke(Expression.Constant(falseExpression))); 

var λ = Expression.Lambda(e).Compile(); 

b = true; 
λ.DynamicInvoke(); 

b = false; 
λ.DynamicInvoke(); 

Esto produce la salida:

True 
False 

El paso en el que la expresión se compila en un Lambda puede ser un rendimiento significativo éxito, tendrá que para llegar a una estrategia de almacenamiento en caché para sus lambdas compilados. Sin embargo, vale la pena, llamar al lambda compilado usando DynamicInvoke es muy rápido. Casi tan rápido como si lo hubieras precompilado. Esta técnica es significativamente más rápida que usar la generación de código CodeDom (que requiere un proceso completo para hacer la compilación) y tiene el beneficio principal de producir ensamblajes descargables.

La única limitación es que no puede crear tipos con esta API. Tienes que limitarte a expresiones y declaraciones. Sin embargo, es bastante poderoso, esta es la tripa mágica del DLR.

+1

¿Cómo se obtiene el símbolo lambda? ¡Querer! – usr

+1

Copiar pegar! Es solo un personaje Unicode. Válido en C#. –

Cuestiones relacionadas