I'm attempting to build out some additional feature for a rules engine that I'm working on using Expression Trees which is based on this post - How to implement a rule engine?
One of the rules I have is to add minutes to a property if that properties type is found to be a DateTime. So for example I could have "DOB + 60" or "DOB - 180".
My current code is working for this:
var expression = new string[] {"DOB", "+", "60"};
var property = Expression.Property(param, expression[0]);
var method = typeof(T).GetProperty(expression[0]).PropertyType.GetMethod("AddMinutes");
/* If we have a AddMinutes method then assume type is of DateTime */
if (method != null)
{
var tParam = method.GetParameters()[0].ParameterType;
/* Calculate if we're adding or subtracting minutes */
var convertedNo = expression[1] == "-" ? int.Parse(expression[2]) * -1 : int.Parse(expression[2]);
var number = Expression.Constant(Convert.ChangeType(convertedNo, tParam));
var exp = Expression.Call(property, method, number);
/* Allows for left property < DOB.AddMinutes(60) */
return Expression.MakeBinary(ExpressionType.LessThan, left, exp);
}
The trouble I'm having is that the DOB property may be set to DateTime.Min so that when my expression comes to evaluate "DOB - 180" in that case an Out of Bounds exception is thrown as it's attempting to subtract 180 mins from DateTime.Min.
I attempted to get round this issue by using an Expression.IfThenElse so that if the DateTime property is equal to DateTime.Min, don't do the calculation and just evaluate on DateTime.Min.
My updated code looks like this:
var expression = new string[] {"DOB", "-", "180"};
var property = Expression.Property(param, expression[0]);
var method = typeof(T).GetProperty(expression[0]).PropertyType.GetMethod("AddMinutes");
/* If we have a AddMinutes method then assume type is of DateTime */
if (method != null)
{
var tParam = method.GetParameters()[0].ParameterType;
/* Calculate if we're adding or subtracting minutes */
var convertedNo = expression[1] == "-" ? int.Parse(expression[2]) * -1 : int.Parse(expression[2]);
var number = Expression.Constant(Convert.ChangeType(convertedNo, tParam));
var exp = Expression.Call(property, method, number);
var minDate = Expression.Constant(Convert.ChangeType(DateTime.MinValue, typeof(DateTime)));
var minDateCheck = Expression.MakeBinary(ExpressionType.Equal, property, minDate);
var minDateExp = Expression.IfThenElse(minDateCheck, minDate, exp);
/* To allow for left property < DOB == DateTime.Min ? DateTime.Min : DOB.AddMinutes(60) */
return Expression.MakeBinary(ExpressionType.LessThan, left, minDateExp); // Exception thrown here
}
Unfortunately this throws the exception - Cannot compare DateTime with return type of void. I've tried several variations but always get the same exception.
Would anyone be able to show me how I could construct an expression that would be able to do this logic?