User defined formulas in C#
I have an application where for each ob开发者_运维百科ject the user can specify his own measurepoints. The values of theese measurements will then be used to classify the object as i e A - needs service, B - service should be scheduled within X days, C - no service needed ATM
However theese objects can be almost anything and there is no way we can hard code how the measured values should be aggregated to a classification, we need to leave that to the user.
Have you any suggestions on how we can provide a way for the user to enter his own formulas for this? It does not have to be idiot-proof, we dont have that many customers so we can assist them as long as they can explain it to us.
I have written an open source project, Dynamic Expresso, that can convert text expression written using a C# syntax into delegates (or expression tree). Expressions are parsed and transformed into Expression Trees without using compilation or reflection.
You can write something like:
var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");
or
var interpreter = new Interpreter()
.SetVariable("service", new ServiceExample());
string expression = "x > 4 ? service.SomeMethod() : service.AnotherMethod()";
Lambda parsedExpression = interpreter.Parse(expression,
new Parameter("x", typeof(int)));
parsedExpression.Invoke(5);
My work is based on Scott Gu article http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .
Flee expression evaluator
You could give the users a list of variables that are valid to use and let them come up with their own expressions. You would then pass all the expressions, variable names and values to Flee and it would resolve all expressions to a value or true/false.
Your situation is a perfect case for a domain specific language. A DSL would allow you to specify an allowable grammar for your "formula language" and then provide feedback to the user as well as calculate the result.
Antlr is a very good tool for this. It is a parser/lexar generator. Basically you specify the grammar in Antlr's own description DSL, and it generates robust lexers and parsers for you in your language of choice.
For example, if your language allows simple calculations this is how it would be specified in antlr's language (from antlr's wiki):
grammar SimpleCalc;
options {
language=CSharp2;
}
tokens {
PLUS = '+' ;
MINUS = '-' ;
MULT = '*' ;
DIV = '/' ;
}
@members {
public static void Main(string[] args) {
SimpleCalcLexer lex = new SimpleCalcLexer(new ANTLRFileStream(args[0]));
CommonTokenStream tokens = new CommonTokenStream(lex);
SimpleCalcParser parser = new SimpleCalcParser(tokens);
try {
parser.expr();
} catch (RecognitionException e) {
Console.Error.WriteLine(e.StackTrace);
}
}
}
/*------------------------------------------------------------------
* PARSER RULES
*------------------------------------------------------------------*/
expr : term ( ( PLUS | MINUS ) term )* ;
term : factor ( ( MULT | DIV ) factor )* ;
factor : NUMBER ;
/*------------------------------------------------------------------
* LEXER RULES
*------------------------------------------------------------------*/
NUMBER : (DIGIT)+ ;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ;
fragment DIGIT : '0'..'9' ;
You can find out more about DSLs in general here.
SpreadsheetGear for .NET might be a good choice. SpreadsheetGear accepts and calculates formulas in the language most users already know - Excel. SpreadsheetGear includes a Windows Forms spreadsheet control, or you can use it as a library if you are doing ASP.NET or a web service.
You can see simple ASP.NET calculation samples here, or download the free trial here if you want to try the WinForms control.
Disclaimer: I own SpreadsheetGear LLC
You should use .NET 3.5 Expressions, in System.Linq.Expressions. Scott Gu has provided a Dynamic Expression API that allows you to evaluate strings to turn them into expression trees, which may then be evaluated by code either to examine the expression contents, or compiled for execution.
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
You mention the objects can be "almost anything". Can the measure points also be almost anything? Presumably the measurements would be limited to defined properties of the object in question, in which case you could presumably expose a wizard-like editor that would allow the user to perform calculations based on object properties discovered via reflection. One thing you have going for you by way of bounding the problem is you seem to be enforcing 3 endpoints for measurement instead of 1 to N states.
One last suggestion, I think for sufficient flexibility you will need an independent measurement object model that binds to the objects you wish to measure.
How important is it for you to enforce exclusivity on the measurements? Protecting the user from defining overlapping states will perhaps be the toughest piece of this, since from your description it would seem that entirely different measurements are valid to attach to different states.
Also, do you know how you will be polling the objects to calculate measurements to define the state of the objects?
Sorry to speak so generally but really at this point your question is pretty general. Good luck.
Could the user use his knowledge of the object and just decide which category to put it in when he enters it into the system? Guess we need more info but if the user can define which measurepoints determine which category, couldn't they just choose the category?
精彩评论