Create expression for a simple math formula - c#

I have some fun with Expressions and a question appears: it throws an exception that I didn't suppose.
I have an input - simple math formula, for example 2*x+3, and I want to create an expression tree for it. So I write this code
using System;
using System.Linq.Expressions;
namespace ConsoleApplication50
{
class Program
{
static void Main()
{
string s = "3*x^2+2/5*x+4";
Expression<Func<double, double>> expr = MathExpressionGenerator.GetExpression(s);
Console.WriteLine(expr);
var del = expr.Compile();
Console.WriteLine(del(10));
}
}
static class MathExpressionGenerator
{
public const string SupportedOps = "+-*/^";
private static readonly ParameterExpression Parameter = Expression.Parameter(typeof(double), "x");
public static Expression<Func<double, double>> GetExpression(string s)
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(double), "x");
Expression result = GetExpressionInternal(s);
return Expression.Lambda<Func<double, double>>(result, parameterExpression);
}
private static Expression GetExpressionInternal(string s)
{
double constant;
if (s == "x")
return Parameter;
if (double.TryParse(s, out constant))
return Expression.Constant(constant, typeof(double));
foreach (char op in SupportedOps)
{
var split = s.Split(new[] { op }, StringSplitOptions.RemoveEmptyEntries);
if (split.Length > 1)
{
var expression = GetExpressionInternal(split[0]);
for (int i = 1; i < split.Length; i++)
{
expression = RunOp(expression, GetExpressionInternal(split[i]), op);
}
return expression;
}
}
throw new NotImplementedException("never throws");
}
private static Expression RunOp(Expression a, Expression b, char op)
{
switch (op)
{
case '+':
return Expression.Add(a, b);
case '-':
return Expression.Subtract(a, b);
case '/':
return Expression.Divide(a, b);
case '*':
return Expression.Multiply(a, b);
case '^':
return Expression.Power(a, b);
}
throw new NotSupportedException();
}
}
}
but I get an error:
Unhandled Exception: System.InvalidOperationException: variable 'x' of
type 'Sys tem.Double' referenced from scope '', but it is not defined
at
System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpress
ion node, VariableStorageKind storage) at
System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterEx
pression node) at
System.Linq.Expressions.ParameterExpression.Accept(ExpressionVisitor
visit or) at ... and so on
Please, advice, how can it be fixed? Here I have a single global parameter and referencing it so I have no idea, why it says this stuff.

Problem with your code is that you have two instances of x parameter. One of them is private static field that is used across expression generation, and second one is that you create and use in Lambda creation.
If you have ParameterExpression, then you should use the same instance in expression and pass the same instance into Lambda generation, otherwise it will fail like in your example.
it will work fine if you remove parameterExpression and will use private Parameter field like this:
public static Expression<Func<double, double>> GetExpression(string s)
{
Expression result = GetExpressionInternal(s);
return Expression.Lambda<Func<double, double>>(result, Parameter);
}
Working example in .NetFiddle - https://dotnetfiddle.net/Onw0Hy

static void Main(string[] args)
{
var str = #"3*x^2+2/5*x+4";
str = Transform(str);
var param = Expression.Parameter(typeof (double), "x");
var expression = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] {param}, null, str);
var exp10 = expression.Compile().DynamicInvoke(10);
Console.WriteLine(exp10);
}
public const string SupportedOps = "+-*/";//separators without ^
private static string Transform(string expression)
{
//replace x^y with Math.Pow(x,y)
var toBeReplaced = expression.Split(SupportedOps.ToCharArray()).Where(s => s.Contains("^"));
var result = expression;
return toBeReplaced.Aggregate(expression, (current, str) => current.Replace(str, string.Format("Math.Pow({0})", str.Replace('^', ','))));
//OR
//foreach (var str in toBeReplaced)
//{
// result =result.Replace(str, string.Format("Math.Pow({0})", str.Replace('^', ',')));
//}
//return result;
}

Related

Unhandled InvalidOperationException when constructing expression trees

I have been trying to construct an expression tree that will evaluate math expressions in RPN.
I have got an exception when trying to call my MakeBinary expression to calculate numbers in the tree.
The exception is the following "System.InvalidOperationException: 'The binary operator Add is not defined for the types 'System.Char' and 'System.Char'.'"
Here is my code:
public static bool isOp(char checkIt)
{
bool verify;
if(checkIt== '+'|| checkIt== '-'||checkIt== '*' || checkIt== '/'||checkIt== '^')
{
return verify= true;
}
else
{
return verify= false;
}
return verify;
}
public static BinaryExpression myMakeBiniray(char ops,Expression leftOp, Expression rightOp)
{
switch (ops)
{
case '+':
Expression left = leftOp;
Expression right = rightOp;
return Expression.MakeBinary(ExpressionType.Add, left, right);
// return Expression.MakeBinary(ExpressionType.Add, Expression.Constant(2), Expression.Constant(4));
case '-':
return Expression.MakeBinary(ExpressionType.Subtract, Expression.Constant(leftOp), Expression.Constant(rightOp));
case '*':
return Expression.MakeBinary(ExpressionType.Multiply, Expression.Constant(leftOp), Expression.Constant(rightOp));
case '/':
return Expression.MakeBinary(ExpressionType.Divide, Expression.Constant(leftOp), Expression.Constant(rightOp));
case '^':
return Expression.MakeBinary(ExpressionType.Power, Expression.Constant(leftOp), Expression.Constant(rightOp));
default:
return null;
}
}
static void Main(string[] args)
{
Console.WriteLine("Enter mathematical expression : ");
string input = "12+";
Stack<Expression> ex = new Stack<Expression>();
for (int i = 0; i < input.Length; i++)
{
var d = input[i];
if (!isOp(d))
{
Expression constacntNumberExpression = Expression.Constant(d);
ex.Push(constacntNumberExpression);
}
else
{
Expression popLeft = ex.Pop();
Expression popRight = ex.Pop();
BinaryExpression node= myMakeBiniray(d, popLeft, popRight);
ex.Push(node);
}
}
I am struggling to understand the source of the problem,
any help would be greatly appreciated!
You need to convert the input from char to int when you're adding number expressions into the stack.
Change this part of Main:
var d = input[i];
if (!isOp(d))
{
Expression constacntNumberExpression = Expression.Constant(d);
ex.Push(constacntNumberExpression);
}
To:
var d = input[i];
if (!isOp(d) && Char.IsNumber(d))
{
var constantNumber = Char.GetNumericValue(d);
Expression constacntNumberExpression = Expression.Constant(constantNumber);
ex.Push(constacntNumberExpression);
}

Find and remove parameter declaration inside Expression.Block

I know how to replace a parameter with ExpressionVisitor but I was wondering if there's a way to remove a parameter from a Expression.Block.
Ideally I should crawl the entire Expression tree and remove the parameter every time it is declared inside a Block.
Any idea how to do that with ExpressionVisitor?
A simple class to remove local variables from a BlockExpression and replace them with whatever you want.
public class BlockVariableRemover : ExpressionVisitor
{
private readonly Dictionary<Expression, Expression> replaces = new Dictionary<Expression, Expression>();
public readonly Func<ParameterExpression, int, Expression> Replacer;
public BlockVariableRemover(Func<ParameterExpression, int, Expression> replacer)
{
Replacer = replacer;
}
protected override Expression VisitBlock(BlockExpression node)
{
var removed = new List<Expression>();
var variables = node.Variables.ToList();
for (int i = 0; i < variables.Count; i++)
{
var variable = variables[i];
var to = Replacer(variable, i);
if (to != variable)
{
removed.Add(variable);
replaces.Add(variable, to);
variables.RemoveAt(i);
i--;
}
}
if (removed.Count == 0)
{
return base.VisitBlock(node);
}
var expressions = node.Expressions.ToArray();
for (int i = 0; i < expressions.Length; i++)
{
expressions[i] = Visit(expressions[i]);
}
foreach (var rem in removed)
{
replaces.Remove(rem);
}
return Expression.Block(variables, expressions);
}
public override Expression Visit(Expression node)
{
Expression to;
if (node != null && replaces.TryGetValue(node, out to))
{
return base.Visit(to);
}
return base.Visit(node);
}
}
Use it like:
Expression<Func<int, int>> exp;
{
var var1 = Expression.Variable(typeof(int), "var1");
var var2 = Expression.Variable(typeof(long), "var2");
var par1 = Expression.Parameter(typeof(int), "par1");
var block = Expression.Block(new[] { var1, var2 }, Expression.Increment(var1));
exp = Expression.Lambda<Func<int, int>>(block, par1);
// Test
var compiled = exp.Compile();
Console.WriteLine(compiled(10));
}
// Begin replace
{
var par1 = exp.Parameters[0];
var block2 = new BlockVariableRemover(
// ix is the index of the variable,
// return x if you don't want to modify,
// return whatever you want (even Expression.Empty()) to do
// a replace
(x, ix) => ix == 0 && x.Type == typeof(int) ? par1 : x)
.Visit(exp.Body);
// Final result
var exp2 = Expression.Lambda<Func<int, int>>(block2, par1);
// Test
var compiled = exp2.Compile();
Console.WriteLine(compiled(10));
}

Evaluating complex expression tree

I have a basic rule engine that I've built in a very similar way to the route suggested here:
How to implement a rule engine?
Ive extended it based on further requirements, and now I need to evaluate complex classes eg
EvaluateRule("Transaction.IsOpen", "Equals", "true")
The code in its most basic form is:
var param = inputMessageType;
left = Expression.Property(param, memberName);
tProp = typeof(T).GetProperty(r.MemberName).PropertyType;
right = Expression.Constant(Convert.ChangeType(r.TargetValue, tProp));
return Expression.MakeBinary(tBinary, left, right);
In order to evaluate complex classes I used a method similar to here:
https://stackoverflow.com/questions/16544672/dynamically-evaluating-a-property-string-with-expressions
The problem that Im having is that when I try to evaluate the rule with a property of a class (Transaction.IsOpen), I get it with the type of the root type on the right hand side of the expression but the type of the complex object on the left hand side of the expression.
This results in the error:
System.InvalidOperationException: The binary operator Equal is not defined for the types 'System.Func`2[Transaction,System.Boolean]' and 'System.Boolean'.
How do I overcome this problem? I am no expert using Expression Trees, and many of the concepts are proving difficult to grasp when the example strays from the standard documentation.
Edit: Here is the code(Ive omitted some stuff that is environment specific so as keep focus with the problem)
public Actions EvaluateRulesFromMessage(ClientEventQueueMessage message)
{
var ruleGroups = _ruleRepository.GetRuleList();
var actions = new Actions();
foreach (var ruleGroup in ruleGroups)
{
if (message.MessageType == "UI_UPDATE")
{
// clean up json object
JObject dsPayload = (JObject.Parse(message.Payload));
var msgParams = JsonConvert.DeserializeObject<UiTransactionUpdate>(message.Payload);
msgParams.RulesCompleted = msgParams.RulesCompleted ?? new List<int>();
var conditionsMet = false;
// process the rules filtering out the rules that have already been evaluated
var filteredRules = ruleGroup.Rules.Where(item =>
!msgParams.RulesCompleted.Any(r => r.Equals(item.Id)));
foreach (var rule in filteredRules)
{
Func<UiTransactionUpdate, bool> compiledRule = CompileRule<UiTransactionUpdate>(rule, msgParams);
if (compiledRule(msgParams))
{
conditionsMet = true;
}
else
{
conditionsMet = false;
break;
}
}
if (conditionsMet)
{
actions = AddAction(message, ruleGroup);
break;
}
}
}
return actions;
}
public Func<UiTransactionUpdate, bool> CompileRule<T>(Rule r, UiTransactionUpdate msg)
{
var expression = Expression.Parameter(typeof(UiTransactionUpdate));
Expression expr = BuildExpr<UiTransactionUpdate>(r, expression, msg);
// build a lambda function UiTransactionUpdate->bool and compile it
return Expression.Lambda<Func<UiTransactionUpdate, bool>>(expr, expression).Compile();
}
static Expression Eval(object root, string propertyString, out Type tProp)
{
Type type = null;
var propertyNames = propertyString.Split('.');
ParameterExpression param = Expression.Parameter(root.GetType());
Expression property = param;
string propName = "";
foreach (var prop in propertyNames)
{
property = MemberExpression.PropertyOrField(property, prop);
type = property.Type;
propName = prop;
}
tProp = Type.GetType(type.UnderlyingSystemType.AssemblyQualifiedName);
var param2 = MemberExpression.Parameter(tProp);
var e = Expression.Lambda(property, param);
return e;
}
static Expression BuildExpr<T>(Rule r, ParameterExpression param, UiTransactionUpdate msg)
{
Expression left;
Type tProp;
string memberName = r.MemberName;
if (memberName.Contains("."))
{
left = Eval(msg, memberName, out tProp);
}
else
{
left = Expression.Property(param, memberName);
tProp = typeof(T).GetProperty(r.MemberName).PropertyType;
}
ExpressionType tBinary;
if (ExpressionType.TryParse(r.Operator, out tBinary))
{
Expression right=null;
switch (r.ValueType) ///todo: this needs to be refactored to be type independent
{
case TargetValueType.Value:
right = Expression.Constant(Convert.ChangeType(r.TargetValue, tProp));
break;
}
// use a binary operation ie true/false
return Expression.MakeBinary(tBinary, left, right);
}
else
{
var method = tProp.GetMethod(r.Operator);
var tParam = method.GetParameters()[0].ParameterType;
var right = Expression.Constant(Convert.ChangeType(r.TargetValue, tParam));
// use a method call, e.g. 'Contains' -> 'u.Tags.Contains(some_tag)'
return Expression.Call(left, method, right);
}
}
The sample code does not cover all data types used in your scenario, so it's hard to tell where it breaks exactly, but from the exception System.Func'2[Transaction,System.Boolean]' and 'System.Boolean it's obvious that on left hand you have a delegate that takes in Transaction and returns bool (Func<Transaction, bool>), and on the right hand you just have bool.
It's not possible to compare Func<Transaction, bool> to bool, but it's possible to call the function and compare its result:
Func<Transaction, bool> func = ...;
bool comparand = ...;
Transaction transaction = ...;
if (func(transaction) == comparand) { ... }
What translated to expression tree:
Expression funcExpression = ... /*LambdaExpression<Func<Transaction,bool>>*/;
Expression comparandExpression = Expression.Constant(true);
Expression transactionArg = /*e.g.*/Expression.Constant(transaction);
Expression funcResultExpression = Expression.Call(funcExpression, "Invoke", null, transactionArg);
Expression equalityTestExpression = Expression.Equal(funcResultExpression, comparandExpression);

Like operator or using wildcards in LINQ to Entities

I'm using LINQ 2 Entities.
Following is the problem:
string str = '%test%.doc%'
.Contains(str) // converts this into LIKE '%~%test~%.doc~%%'
Expected Conversion: LIKE '%test%.doc%'
If it was LINQ 2 SQL, I could have used SqlMethods.Like as somebody answered it in my previous question. But now as I'm using L2E not L2S, I need other solution.
The SQL method PATINDEX provides the same functionality as LIKE. Therefore, you can use the SqlFunctions.PatIndex method:
.Where(x => SqlFunctions.PatIndex("%test%.doc%", x.MySearchField) > 0)
Following on from Magnus' correct answer, here is an extension method that can be re-used, as I needed in my project.
public static class LinqExtensions
{
public static Expression<Func<T, bool>> WildCardWhere<T>(this Expression<Func<T, bool>> source, Expression<Func<T, string>> selector, string terms, char separator)
{
if (terms == null || selector == null)
return source;
foreach (string term in terms.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries))
{
string current = term;
source = source.And(
Expression.Lambda<Func<T, bool>>(
Expression.Call(selector.Body, "Contains", null, Expression.Constant(current)),
selector.Parameters[0]
)
);
}
return source;
}
}
Usage:
var terms = "%test%.doc%";
Expression<Func<Doc, bool>> whereClause = d => d;
whereClause = whereClause.WildCardWhere(d => d.docName, terms, '%');
whereClause = whereClause.WildCardWhere(d => d.someOtherProperty, "another%string%of%terms", '%');
var result = ListOfDocs.Where(whereClause).ToList();
The extension makes use of the predicate builder at http://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/. The resulting sql does a single table scan of the table, no matter how many terms are in there. Jo Vdb has an example you could start from if you wanted an extension of iQueryable instead.
You can try use this article, where author describes how to build a LIKE statement with wildcard characters in LINQ to Entities.
EDIT: Since the original link is now dead, here is the original extension class (as per Jon Koeter in the comments) and usage example.
Extension:
public static class LinqHelper
{
//Support IQueryable (Linq to Entities)
public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> valueSelector, string value, char wildcard)
{
return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
}
//Support IEnumerable (Linq to objects)
public static IEnumerable<TSource> WhereLike<TSource>(this IEnumerable<TSource> sequence, Func<TSource, string> expression, string value, char wildcard)
{
var regEx = WildcardToRegex(value, wildcard);
//Prevent multiple enumeration:
var arraySequence = sequence as TSource[] ?? sequence.ToArray();
try
{
return arraySequence.Where(item => Regex.IsMatch(expression(item), regEx));
}
catch (ArgumentNullException)
{
return arraySequence;
}
}
//Used for the IEnumerable support
private static string WildcardToRegex(string value, char wildcard)
{
return "(?i:^" + Regex.Escape(value).Replace("\\" + wildcard, "." + wildcard) + "$)";
}
//Used for the IQueryable support
private static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(Expression<Func<TElement, string>> valueSelector, string value, char wildcard)
{
if (valueSelector == null) throw new ArgumentNullException("valueSelector");
var method = GetLikeMethod(value, wildcard);
value = value.Trim(wildcard);
var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value));
var parameter = valueSelector.Parameters.Single();
return Expression.Lambda<Func<TElement, bool>>(body, parameter);
}
private static MethodInfo GetLikeMethod(string value, char wildcard)
{
var methodName = "Equals";
var textLength = value.Length;
value = value.TrimEnd(wildcard);
if (textLength > value.Length)
{
methodName = "StartsWith";
textLength = value.Length;
}
value = value.TrimStart(wildcard);
if (textLength > value.Length)
{
methodName = (methodName == "StartsWith") ? "Contains" : "EndsWith";
}
var stringType = typeof(string);
return stringType.GetMethod(methodName, new[] { stringType });
}
}
Usage Example:
string strEmailToFind = "%#yahoo.com"
IQueryable<User> myUsers = entities.Users.WhereLike(u => u.EmailAddress, strEmailToFind, '%');
or, if you expect your users to be more accustomed to Windows Explorer-styled wildcards:
string strEmailToFind = "*#yahoo.com"
IQueryable<User> myUsers = entities.Users.WhereLike(u => u.EmailAddress, strEmailToFind, '*');
Use a regular expression...
The following will print out all of the files in the current directory that match test.doc* (dos wildcard style - which I believe is what you're asking for)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace RegexFileTester
{
class Program
{
static void Main(string[] args)
{
string[] _files = Directory.GetFiles(".");
var _fileMatches = from i in _files
where Regex.IsMatch(i, ".*test*.doc.*")
//where Regex.IsMatch(i, ".*cs")
select i;
foreach(var _file in _fileMatches)
{
Console.WriteLine(_file);
}
}
}
}
Split the String
var str = "%test%.doc%";
var arr = str.Split(new[]{'%'} ,StringSplitOptions.RemoveEmptyEntries);
var q = tblUsers.Select (u => u);
foreach (var item in arr)
{
var localItem = item;
q = q.Where (x => x.userName.Contains(localItem));
}
So I was trying the same thing - trying to pair down a List to return all candidates that matched a SearchTerm. I wanted it so that if a user typed "Arizona" it would return everything regardless of case that had Arizona. Also, if the user typed "Arizona Cha", it would return items like "Arizona License Change". The following worked:
private List<Certification> GetCertListBySearchString()
{
string[] searchTerms = SearchString.Split(' ');
List<Certification> allCerts = _context.Certifications.ToList();
allCerts = searchTerms.Aggregate(allCerts, (current, thisSearchString) => (from ac in current
where ac.Name.ToUpper().Contains(thisSearchString.ToUpper())
select ac).ToList());
return allCerts;
}

Parse string into int32 using expressions in C#

Basically I've wrote my own parser and I'm parsing a string into and expression and then compiling and storing to be reused later on.
For (an odd) example the type of string I'm parsing is this:-
if #name == 'max' and #legs > 5 and #ears > 5 then shoot()
The hash parts in the string are telling my parser to look at the properties on the object of type T that I pass in, if not found to look in a Dictionary that also gets passed in as extra.
I parse up the string into parts create an expression and join the expressions using methods from the PredicateBuilder.
I get the left value from where ever it may be and then the right value and turn it into an int32 or a string based on if it's wrapped in single quotes.. for now, then pass both into Expression.Equals/Expression.GreaterThan etc. dependant on the operator.
So far this works fine for equals and strings but take for example #ears which isn't a property on the object but is in the dictionary I end up with "does string equal int32" and it throws an exception.
I need to be able to parse the string from the dictionary into and int32 and then try the equal/greater/less than method.
Hopefully someone could shed some light on this as I haven't found anything yet that will do it and its driving me mad.
Here is the CreateExpression method I'm using to create an expression from the string.
private Expression<Func<T, IDictionary<string, string>, bool>> CreateExpression<T>(string condition)
{
string[] parts = condition.Split(new char[] { ' ' }, 3, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 3)
{
var typeCache = _cache[typeof(T).FullName];
var param = Expression.Parameter(typeCache.T, "o");
var param2 = Expression.Parameter(typeof(IDictionary<string, string>), "d");
/* Convert right hand side into correct value type
*/
Expression right = null;
if (parts[2][0] == '\'' && parts[2][parts[2].Length - 1] == '\'')
right = Expression.Constant(parts[2].Trim(new char[] { '\'' }), typeof(string));
else
{
int x = 0;
right = (int.TryParse(parts[2].Trim(), out x))
? Expression.Constant(x)
: Expression.Constant(parts[2].Trim(new char[] { '\'' }), typeof(string));
}
/* Get the left hand side value from object T or IDictionary and then attempt to convert it
* into the right hand side value type
*/
Expression left = null;
var key = (parts[0][0] == '#') ? parts[0].TrimStart('#') : parts[0];
if (_cache[typeCache.T.FullName].Properties.Find(key, true) == null)
{
var m = typeof(ExpressionExtensions).GetMethod("GetValue");
left = Expression.Call(null, m, new Expression[] { param2, Expression.Constant(key) });
}
else
left = Expression.PropertyOrField(param, key);
/* Find the operator and return the correct expression
*/
if (parts[1] == "==")
{
return Expression.Lambda<Func<T, IDictionary<string, string>, bool>>(
Expression.Equal(left, right), new ParameterExpression[] { param, param2 });
}
else if (parts[1] == ">")
{
return Expression.Lambda<Func<T, IDictionary<string, string>, bool>>(
Expression.GreaterThan(left, right), new ParameterExpression[] { param, param2 });
}
}
return null;
}
And here is the method to parse the whole string into parts and build up the expression.
public Func<T, IDictionary<string, string>, bool> Parse<T>(string rule)
{
var type = typeof(T);
if (!_cache.ContainsKey(type.FullName))
_cache[type.FullName] = new TypeCacheItem()
{
T = type,
Properties = TypeDescriptor.GetProperties(type)
};
Expression<Func<T, IDictionary<string, string>, bool>> exp = null;
var actionIndex = rule.IndexOf("then");
if (rule.IndexOf("if") == 0 && actionIndex > 0)
{
var conditionStatement = rule.Substring(2, actionIndex - 2).Trim();
var actionStatement = rule.Substring(actionIndex + 4).Trim();
var startIndex = 0;
var endIndex = 0;
var conditionalOperator = "";
var lastConditionalOperator = "";
do
{
endIndex = FindConditionalOperator(conditionStatement, out conditionalOperator, startIndex);
var condition = (endIndex == -1) ? conditionStatement.Substring(startIndex) : conditionStatement.Substring(startIndex, endIndex - startIndex);
var x = CreateExpression<T>(condition.Trim());
if (x != null)
{
if (exp != null)
{
switch (lastConditionalOperator)
{
case "or":
exp = exp.Or<T>(x);
break;
case "and":
exp = exp.And<T>(x);
break;
default:
exp = x;
break;
}
}
else
exp = x;
}
lastConditionalOperator = conditionalOperator;
startIndex = endIndex + conditionalOperator.Length;
} while (endIndex > -1);
}
else
throw new ArgumentException("Rule must start with 'if' and contain 'then'.");
return (exp == null) ? null : exp.Compile();
}
My eyes are open to suggestions or advice on this but the idea of parsing that string as is to return true or false has to be,
EDIT:
I've now alter my method that retrieves the value from the dictionary to a generic one as Fahad suggested to this:-
public static T GetValue<T>(this IDictionary<string, string> dictionary, string key)
{
string x = string.Empty;
dictionary.TryGetValue(key, out x);
if (typeof(T) == typeof(int))
{
int i = 0;
if (int.TryParse(x, out i))
return (T)(i as object);
}
return default(T);
//throw new ArgumentException("Failed to convert dictionary value to type.");
}
And this works fine but I would rather return null than a default value for the type i've tried using Nullable ... where T : struct and returning null when not found or can't convert but I don't know how to use the null result in my expression.
I think you should redo your problem analysis and try another way. One way I would propose is to have a generic method that would give you the value from a IDictionary or IList etc., and use this method to wrap around your Expression's. The Expression would only want the "Type" of the object to be satisfied, if that is done correctly, then you could easily do it. If you know the "Type" then you can implement it with generic methods, otherwise, you could still use reflection and do generics.
So all you have to think is how to get the value from the dictionary or any other list through expressions.
Hope that helps.
-Fahad
You could use Expression.Call(null, typeof(int), "Parse", Type.EmptyTypes, yourTextExpression)

Categories