出现错误:未为类型'System.Guid'和'System.String'定义二进制运算符Equal

Fra*_*aki 4 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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

当我通过此代码生成表达式时

 delegExpFilters = EntityExpression.ExpressionBuilder.GetExpression<Contact>(domainFilter).Compile();
Run Code Online (Sandbox Code Playgroud)

我的domainFilter包含具有属性字段名称,操作符及其值的列表记录,而我的字段是GUID

当我调用GetExpression时,给我错误错误没有为类型'System.Guid'和'System.String'定义二进制运算符Equal

Ser*_*kiy 8

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

ConstantExpression constant = Expression.Constant(filter.Value);
Run Code Online (Sandbox Code Playgroud)

考虑您具有名为的整数属性过滤器Amount

var filter = new Filter {
   PropertyName = "Amount",
   Operation = Op.GreaterThan,
   Value = "42"
};
Run Code Online (Sandbox Code Playgroud)

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

contract.Amount > "42"
Run Code Online (Sandbox Code Playgroud)

不允许将这种整数与字符串进行比较。


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

  1. 获取属性类型的类型转换器
  2. 检查是否可以将字符串转换为属性类型
  3. 进行转换(将返回属性值作为 object
  4. 创建转换表达式以将属性值从转换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
Run Code Online (Sandbox Code Playgroud)

您应该在返回的二进制表达式中使用此值表达式而不是常量表达式。例如:

case Op.LessThan:
    return Expression.LessThan(member, valueExpression);
case Op.Equal:
    return Expression.Equal(member, valueExpression);
// etc
Run Code Online (Sandbox Code Playgroud)

为了平等,您也应该使用二进制表达式。现在,过滤器Amount将被转换为

 contract.Amount > (int)42
Run Code Online (Sandbox Code Playgroud)