This is My Expression Class
public static class ExpressionBuilder
{
private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
private static MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
private static MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
public static Expression<Func<T,
bool>> GetExpression<T>(IList<Filter> filters)
{
if (filters.Count == 0)
return null;
ParameterExpression param = Expression.Parameter(typeof(T), "t");
Expression exp = null;
if (filters.Count == 1)
exp = GetExpression<T>(param, filters[0]);
else if (filters.Count == 2)
exp = GetExpression<T>(param, filters[0], filters[1]);
else
{
while (filters.Count > 0)
{
var f1 = filters[0];
var f2 = filters[1];
if (exp == null)
exp = GetExpression<T>(param, filters[0], filters[1]);
else
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1]));
filters.Remove(f1);
filters.Remove(f2);
if (filters.Count == 1)
{
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0]));
filters.RemoveAt(0);
}
}
}
return Expression.Lambda<Func<T, bool>>(exp, param);
}
private static Expression GetExpression<T>(ParameterExpression param, Filter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
ConstantExpression constant = Expression.Constant(filter.Value);
switch (filter.Operation)
{
case Op.Equals:
return Expression.Equal(member, Expression.Call(Expression.Convert(Expression.Constant(search.RetrieveGuid), typeof(object)), typeof(object).GetMethod("ToString"))), constant);
case Op.GreaterThan:
return Expression.GreaterThan(member, constant);
case Op.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(member, constant);
case Op.LessThan:
return Expression.LessThan(member, constant);
case Op.LessThanOrEqual:
return Expression.LessThanOrEqual(member, constant);
case Op.Contains:
return Expression.Call(member, containsMethod, constant);
case Op.StartsWith:
return Expression.Call(member, startsWithMethod, constant);
case Op.EndsWith:
return Expression.Call(member, endsWithMethod, constant);
}
return null;
}
private static BinaryExpression GetExpression<T>
(ParameterExpression param, Filter filter1, Filter filter2)
{
Expression bin1 = GetExpression<T>(param, filter1);
Expression bin2 = GetExpression<T>(param, filter2);
return Expression.AndAlso(bin1, bin2);
}
}
when i generate Expression by this code
delegExpFilters = EntityExpression.ExpressionBuilder.GetExpression<Contact>(domainFilter).Compile();
my domainFilter Contains a list records with Property field name ,operator, and its value and my field is GUID
when i call GetExpression it gives me error The binary operator Equal is not defined for the types 'System.Guid' and 'System.String'
You are not converting filter value (which is string) to appropriate type:
ConstantExpression constant = Expression.Constant(filter.Value);
Consider you have filter for integer property named Amount
:
var filter = new Filter {
PropertyName = "Amount",
Operation = Op.GreaterThan,
Value = "42"
};
Your code will generate expression which equivalent of following code
contract.Amount > "42"
Such integer comparison with string is not allowed.
You should get property type and convert filter value to that type. Here are the steps:
object
object
to property typeHere is code of GetExpression
method
var member = Expression.Property(param, filter.PropertyName);
var propertyType = ((PropertyInfo)member.Member).PropertyType;
var converter = TypeDescriptor.GetConverter(propertyType); // 1
if (!converter.CanConvertFrom(typeof(string))) // 2
throw new NotSupportedException();
var propertyValue = converter.ConvertFromInvariantString(filter.Value); // 3
var constant = Expression.Constant(propertyValue);
var valueExpression = Expression.Convert(constant, propertyType); // 4
You should use this value expression instead of your constant expression in binary expressions which you are returning. E.g.:
case Op.LessThan:
return Expression.LessThan(member, valueExpression);
case Op.Equal:
return Expression.Equal(member, valueExpression);
// etc
For equality you should use binary expression as well. And now filter for Amount
will be translated into
contract.Amount > (int)42
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With