这是我的表达类
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);
}
}
当我通过此代码生成Expression
时 delegExpFilters = EntityExpression.ExpressionBuilder.GetExpression<Contact>(domainFilter).Compile();
我的domainFilter包含一个列表记录 属性字段名称,运算符及其值和我的字段是GUID
当我调用GetExpression时,它会给我错误 二进制运算符Equal未定义类型&#39; System.Guid&#39;和&#39; System.String&#39;
答案 0 :(得分:4)
您没有将过滤器值(字符串)转换为适当的类型:
ConstantExpression constant = Expression.Constant(filter.Value);
考虑您对名为Amount
的整数属性进行过滤:
var filter = new Filter {
PropertyName = "Amount",
Operation = Op.GreaterThan,
Value = "42"
};
您的代码将生成与以下代码等效的表达式
contract.Amount > "42"
不允许与字符串进行此类整数比较。
您应该获取属性类型并将过滤器值转换为该类型。以下是步骤:
object
object
转换为属性类型以下是GetExpression
方法的代码
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
您应该在返回的二进制表达式中使用此值表达式而不是常量表达式。 E.g:
case Op.LessThan:
return Expression.LessThan(member, valueExpression);
case Op.Equal:
return Expression.Equal(member, valueExpression);
// etc
对于相等,您也应该使用二进制表达式。现在,Amount
的过滤器将被翻译为
contract.Amount > (int)42