I have a criteria object in which I was to turn each property into a func, if it\'s value isn\'t null.
public class TestClassCriteria
{
public bool? Colu
Your current expression is comparing the property names, but I think you want to be comparing the property values:
var funcs = new List<Func<dynamic, bool>>();
foreach (var property in criteria.GetType().GetProperties())
{
funcs.Add(x => x.GetType().GetProperty(property.Name).GetValue(x, null) == property.GetValue(criteria, null));
}
However, are you sure you need to do this? There would probably be a better way to refactor your code so that you don't need to use reflection to compare properties that happen to have the same name on two unrelated objects.
Do you want something like this?
static List<Func<TEntity, TCriteria, bool>> GetCriteriaFunctions<TEntity, TCriteria>()
{
var criteriaFunctions = new List<Func<TEntity, TCriteria, bool>>();
// searching for nullable properties of criteria
var criteriaProperties = typeof(TCriteria)
.GetProperties()
.Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>));
foreach (var property in criteriaProperties)
{
// this is entity parameter
var entityParameterExpression = Expression.Parameter(typeof(TEntity));
// this is criteria parameter
var criteriaParameterExpression = Expression.Parameter(typeof(TCriteria));
// this is criteria property access: "criteria.SomeProperty"
var criteriaPropertyExpression = Expression.Property(criteriaParameterExpression, property);
// this is testing for equality between criteria property and entity property;
// note, that criteria property should be converted first;
// also, this code makes assumption, that entity and criteria properties have the same names
var testingForEqualityExpression = Expression.Equal(
Expression.Convert(criteriaPropertyExpression, property.PropertyType.GetGenericArguments()[0]),
Expression.Property(entityParameterExpression, property.Name));
// criteria.SomeProperty == null ? true : ((EntityPropertyType)criteria.SomeProperty == entity.SomeProperty)
var body = Expression.Condition(
Expression.Equal(criteriaPropertyExpression, Expression.Constant(null)),
Expression.Constant(true),
testingForEqualityExpression);
// let's compile lambda to method
var criteriaFunction = Expression.Lambda<Func<TEntity, TCriteria, bool>>(body, entityParameterExpression, criteriaParameterExpression).Compile();
criteriaFunctions.Add(criteriaFunction);
}
return criteriaFunctions;
}
Sample entity and sample criteria:
class CustomerCriteria
{
public int? Age { get; set; }
public bool? IsNew { get; set; }
}
class Customer
{
public string Name { get; set; }
public int Age { get; set; }
public bool IsNew { get; set; }
}
Usage:
var criteriaFunctions = GetCriteriaFunctions<Customer, CustomerCriteria>();
var customer1 = new Customer { Name = "John", Age = 35, IsNew = false };
var customer2 = new Customer { Name = "Mary", Age = 27, IsNew = true };
var criteria1 = new CustomerCriteria { Age = 35 };
var criteria2 = new CustomerCriteria { IsNew = true };
Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer1, criteria1)));
Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer2, criteria1)));
Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer1, criteria2)));
Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer2, criteria2)));
Instead of your code with dynamics, this code uses strongly typed member access, so, you could cache list of criteria for each pair "Entity - Criteria" and test instances form matching faster.