2011-02-01 13 views
8

¿Existe algún motor de cálculo para C# que pueda volver a calcular automáticamente los campos dependientes cuando cambie un valor?Tal cosa como un motor de cálculo para C#?

Déjame estilo libre por un segundo, me estoy imaginando algo como esto ..

Field<double> quantity = Field.Create<double>("Quantity"); 
Field<double> unitCost = Field.Create<double>("Unit Cost"); 
Field<double> total = Field.Create<double>("Total"); 

total.Calculation((q,uc) => q * uc, quantity, value); 
     // would have signature something like this: 
     // void Calculation<TR,T1,T1>(Func<TR,T1,T2>, Field<T1>, Field<T2>) 

Esto sería configurar campos que se propagan los valores de auto-dependientes.

quantity.Value = 5.0; 
unitCost.Value = 1.5; 
Assert.That(total.Value, Is.EqualTo(7.5)); 

Obviamente, esto es un ejemplo sencillo, los usos finales serían mucho más afín a los cálculos de una hoja de cálculo complejo.

Pensando aún más sería increíble si el campo/las células soportarían la notificación de cambio.

+3

Busque el "motor de reglas" en Windows Workflow Foundation. –

+0

No sé si ya existe, pero parece que es bueno implementarlo de todos modos, 'solo' necesita INotifyPropertyChanging y descomponer el Árbol de Expresión para vincular las distintas dependencias. – Guillaume86

Respuesta

5

¿Has visto http://ncalc.codeplex.com?

Es extensible, rápido (por ejemplo, tiene su propio caché) le permite proporcionar funciones personalizadas y variables en tiempo de ejecución mediante el manejo de eventos EvaluateFunction/EvaluateParameter. Expresiones de ejemplo que puede analizar:

Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)"); 

    e.Parameters["Pi2"] = new Expression("Pi * Pi"); 
    e.Parameters["X"] = 10; 

    e.EvaluateParameter += delegate(string name, ParameterArgs args) 
    { 
     if (name == "Pi") 
     args.Result = 3.14; 
    }; 

    Debug.Assert(117.07 == e.Evaluate()); 

También maneja Unicode & muchos tipo de datos de forma nativa. Viene con un archivo de astas si quieres cambiar la gramática. También hay un tenedor que soporta MEF para cargar nuevas funciones.

También es compatible con operadores lógicos, cadenas de fecha/hora y declaraciones if.

una solución

Usted podría hacer el recálculo automático mediante la implementación de INotifyPropertyChanged luego hacer algo como

  • establecer expresión this.Field.Expression de un campo nuevo = Expresión ("Campo1 Campo2 + ");

En notifypropertyupdated en la clase

  • para cada campo (con la reflexión) que es una función
  • si se trata de la expresión se refiere al campo modificado luego volver a calcular la variable.
  • al recálculo que había necesidad de controlar el evento EvaluateParameter utilizar la reflexión para encontrar el jardín derecho y extraer su valor (se puede almacenar en caché para evitar la reflexión, si es necesario)
+0

Proyecto interesante: ¿maneja dependencias? es decir¿Puedo construir una serie de expresiones que se basan en los resultados de otras expresiones? Si están en el orden incorrecto (o si más tarde cambia el valor de algo usado por un ex - ¿se encargará de la actualización en cascada?) La documentación parece evitar el tema (tal vez estoy buscando en el lugar equivocado) – Rudu

+0

@Rudu "maneja dependencias", manejará un DAG de expresiones que se mueven desde la primera expresión a través de expresiones especificadas como parámetros a esa expresión y luego a expresiones especificadas como parámetros de esas expresiones, etc. De esta forma, nunca obtendrá una dependencia circular y la orden de cálculo siempre debe ser correcta. Las dependencias sicne se calculan primero. – GreyCloud

+0

@Rudu: el último ejemplo en http://ncalc.codeplex.com/ muestra cómo se puede realizar la anidación. Sobre el tema de las actualizaciones en cascada. No, esto no ocurrirá, el valor que obtiene es el valor calculado en ese momento. Tendría que ordenar las actualizaciones en cascada a través de algo como INotifyPropertyChanged en la clase que contiene los datos – GreyCloud

1

me hizo una pregunta similar aquí: Truly declarative language?

Por lo que yo sé, solo he oído hablar de NCalc, lo investigaré. Tengo un proyecto que hace más o menos lo que describes y luego algo como el almacenamiento en caché/caché de cambios en los valores o la estructura del modelo. Piénselo como un cruce entre una base de datos y Excel. También puede definir clases, etc. y unirlas en modelos grandes con millones de objetos en gráficos, no solo árboles. Servidor de cliente, etc. También hay un editor de modelos en el que se crean modelos en una interfaz de usuario para que pueda analizar cómo todos los cálculos se complementan entre sí.

¿Por qué exactamente estás preguntando?

1

Recomendaría también echarle un vistazo a Jace. Jace es un motor de cálculo más moderno para .NET Framework. Es mucho más rápido que el NCalc propuesto anteriormente. Además, es compatible con más plataformas (.NET, WinRT, WP7 y WP8).

Más información sobre Jace se puede encontrar en la página de GitHub: https://github.com/pieterderycke/Jace

enlace NuGet: https://www.nuget.org/packages/Jace

1

Hay motores de cálculo para los parámetros escalares, y hay motores de cálculo de nivel superior para las tablas, normalmente se usa para aplicaciones como planificación financiera, cálculos de honorarios y comisiones, cálculos de redes y contratos ...

Déjenme explicar esto en breve. Considere seguir fórmulas para escalares:

1) z = f1(x,y) 
2) p = f2(z,n) 
3) q = f3(x,p) 
... 

y así sucesivamente. La configuración de tales funciones y árboles de dependencias requiere un motor de cálculo con parámetros escalares. Yo (también) recomendaría el siguiente enlace para dicho motor de cálculo escrito en C# como un buen punto de partida: http://www.codeproject.com/Articles/246374/A-Calculation-Engine-for-NET

Como se mencionó, también hay motores de cálculo con funciones de tabla que toman tablas como parámetros. El principio principal es el mismo:

1) (T4, T5) = TableFunction1(T1, T2, T3) 
2) (T7, T8) = TableFunction2(T2, T4) 
... 

y así sucesivamente. Tenga en cuenta que una función de tabla puede devolver varias tablas como salidas, como se muestra arriba.

allí dos cuestiones clave que deben observarse aquí:

a) Los valores de las tablas T7 y T8 dependen de las tablas T2 y T4. Por lo tanto, las tablas T7 y T8 deben actualizarse ejecutando la función "TableFunction2" solo si hay un cambio en uno de los parámetros de entrada T2 o T4.

Del mismo modo, T4 necesita actualizarse solo si se actualiza T1, T2 o T3; árbol de dependencia!

b) Separación de la base de datos del proceso de cálculo: el motor de cálculo debe trabajar independientemente de cualquier estructura de datos fija o esquema de base de datos para que pueda integrarse con cualquier base de datos y estructura de datos.

Puede encontrar mi artículo relacionado que estos principios se explican en:

Arquitectura lógica de un marco de cálculo basada en reglas http://finaquant.com/logical-architecture-of-a-rule-based-calculation-framework/1053

Ahora, un C#/biblioteca de red para un motor de cálculo con tablas. ya que los parámetros de entrada y salida se están desarrollando en base a estos principios.

Nota para los moderadores: elimine el enlace de arriba si se cuenta como autopromoción.

+0

Otro buen punto de partida: http: //www.codeproject .com/Articles/17853/Implementing-an-Excel-like-formula-engine – tuncalik

Cuestiones relacionadas