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? ColumnA { get; set; }
public bool? ColumnB { get; set; }
}
This is what I have thus far, but I am pretty sure I am not defining the lambda correct. This is what I trying to achieve. funcs.Add(x => x.ColumnA == criteria.ColumnA)
.
var properties = criteria.GetType().GetProperties();
var funcs = new List<Func<dynamic, bool>>();
foreach (var property in properties)
{
var propertyName = property.Name;
funcs.Add(x => x.GetType().GetProperty(propertyName).Name == criteria.GetType().GetProperty(propertyName).Name);
}
It's not crashing or causing any error, it just isn't working.
Any help you can provide would be greatly appreciated.
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.
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.