Introduction

This is a simple mathematical and logical C# expression evaluator using Expression trees.

C# does not include a built-in method to evaluate a string during runtime, like VBScript's Eval(). I wanted to be able to define a condition "x = c" where x was a property of an runtime object that would vary over calls, and c was a constant, and this condition should be defined in an XML file where it could be changed if needed. I also wanted to ensure that any further conditions could also be defined in this manner, without the need to write any code.

One of the options I found around the internet was to compile the code into a class, load it into memory and call the function through reflection, but I immediately rejected this solution as it was clunky and inelegant.

I then came across Pascal Ganaye's Eval3 library. The library supported passing external variables through a class - just what I needed. It performed well enough (I had to modify the existing code to accommodate the equals operator) but I felt that it was a bit difficult to maintain (had to write a function for each operator-combination type) and I was trying to move away from VB.NET.

I then started working with LINQ and Expression trees and realized I could build my own parser, create an Expression tree and compile it, and even cache the function delegate for optimum speed.

With a bit of help from Wikipedia, I borrowed an implementation of Dijkstra's Shunting-yard algorithm to handle the parsing, rewrote it in C#, threw in Expressions and had the evaluator up and running.

Features

  • C# style operators
  • Arithmetic operators: +- * / % ^
  • Relational operators: = != < > <= >=
  • Logical Operators: ! & | (bitwise logic) && || (short circuit logic)
  • Brackets ( )
  • Index accessor [ ]
  • External variables through a class
  • Strings: enclosed in 'single quotes' and string concatenation
  • DateTimes: #any valid date format#, #Now# returns DateTime.Now
  • true, false, null literals
  • Declarative typing of numbers as double and float using the d and f suffixes
  • Implicit conversion of numerical expressions
  • Member access operator (.) for any valid expression. Access properties, fields and methods of types, objects and expressions
  • Registry of external types and objects
  • Some built-in default types (bool, int, double, float, char, string, DateTime, Convert, Math)
  • Nested function calls (x.method(y.method(z.method()), y.method2()))
  • Compiled expression is cached for speed, useful if expression needs to be evaluated multiple times

Getting Started

See Usage and Sample Expressions under Documentation

Disclaimer

The parser code is in the get-it-working state and may contain bugs.

Last edited Oct 1, 2012 at 1:40 AM by RupertAvery, version 22