获取错误:没有为类型&System; Guid'定义二元运算符Equal。和' System.String'

时间:2017-03-13 15:55:16

标签: c# entity-framework expression-trees

这是我的表达类

        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;

1 个答案:

答案 0 :(得分:4)

您没有将过滤器值(字符串)转换为适当的类型:

ConstantExpression constant = Expression.Constant(filter.Value);

考虑您对名为Amount的整数属性进行过滤:

var filter = new Filter {
   PropertyName = "Amount",
   Operation = Op.GreaterThan,
   Value = "42"
};

您的代码将生成与以下代码等效的表达式

contract.Amount > "42"

不允许与字符串进行此类整数比较。

您应该获取属性类型并将过滤器值转换为该类型。以下是步骤:

  1. 获取属性类型
  2. 的类型转换器
  3. 检查是否可以将字符串转换为属性类型
  4. 执行转换(将属性值返回为object
  5. 创建演员表达式以将属性值从object转换为属性类型
  6. 以下是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