I'm currently developping an simple engine which generates lamda expressions from different classes (using reflexion and expression factories).
I have an issue trying to make some unit tests on my engine.
I use my engine to generate a lambda expression, then I compare the generated lambda with a "hand made" lambda expression. The problem is when I use a DateTime in my lambda expression. The lambda generated with reflection contains an "hard coded" date, whereas in the "hand made" lambda expression, I must use a "new DateTime(...)".
So the unit test fails with the following message (I cut the message to keep only the interresting part) :
Expected: < x => (...) AndAlso (x.Date <= new DateTime(2015, 1, 1)))>
But was: < x => (...) AndAlso (x.Date <= 01/01/2015 00:00:00))>
My assert is the following :
Assert.AreEqual(expectedWhere, request.Filter);
Where "expectedWhere" is the "hand made" lambda and "request.Filter" is the generated lambda.
Is there a solution (like in VB.NET) to create my lambda expression like that :
Expression<Func<Model, bool>> expectedWhere = x => (...) && (x.Date <= [01/01/2015 00:00:00])
I already test to use an external variable, DateTime.Now, or a constant (not managed by the .NET framework).
This is a simple fiddle showing my problem : https://dotnetfiddle.net/fKccY3
Code :
ParameterExpression param = Expression.Parameter(typeof(Model), "x");
var property = Expression.Property(param, "Date");
ConstantExpression constant = Expression.Constant(new DateTime(2015, 1, 1), typeof(DateTime));
Expression finalExpression = Expression.LessThanOrEqual(property, constant);
var tree = Expression.Lambda<Func<Model, bool>>(finalExpression, param);
Console.WriteLine(tree);
Expression<Func<Model, bool>> handMaidExpression = x => x.Date == new DateTime(2015, 1, 1);
Console.WriteLine(handMaidExpression);
Assuming you really mean you want to generate an appropriate expression tree with a ConstantExpression
in, I think you'll have trouble doing that with an actual lambda expression. However, you could construct the relevant expression tree reasonably easily by constructing an expression tree for the rest of it with a lambda expression, and doing the rest manually. Here's a short but complete example:
using System;
using System.Linq.Expressions;
public class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
public class Test
{
public static void Main()
{
Expression<Func<Model, bool>> original = x => x.Name == "Fred";
var parameter = original.Parameters[0];
var dateClause = Expression.LessThanOrEqual(
Expression.Property(parameter, "Date"),
Expression.Constant(new DateTime(2015, 1, 1), typeof(DateTime)));
var combined = Expression.AndAlso(original.Body, dateClause);
var tree = Expression.Lambda<Func<Model, bool>>(combined, parameter);
Console.WriteLine(tree);
}
}
Output:
x => ((x.Name == "Fred") AndAlso (x.Date <= 01/01/2015 00:00:00))
You could fairly easily build this into a utility method if you need it in multiple places.
See more on this question at Stackoverflow