如何在不从 C# 中的 Expression.Convert 转换的情况下获取可空值(字段)的表达式?

How to get Expression for Nullable values ( fields ) without converting from Expression.Convert in C#?

我在动态查询表达式的形成过程中处理 Nullable 类型的扫描。这些表达式将从任何 SQL 表中获取过滤后的数据(使用 EF 与 Code First 类 交互)。

我有普通对象(例如 Consignment 对几个属性以及 Nullable 属性进行操作)。

在遇到一些 Nullable 类型之前,我的表达式构建很顺利。在这些可空值上,我得到

The binary operator NotEqual is not defined for the types 'System.Nullable`1[System.Single]' and 'System.Single'.

为了消除这个异常,我使用了所有关于在不同线程上发布的转换的方法。

Invoking lambda expressions in Expression trees

Trying to filter on a Nullable type using Expression Trees

这些都是生成带有添加词 "Convert" 的表达式(即 Convert(someValue) ),结果我总是有表达式

t=>(t.Consignment.Id = 45000 && t.Consignment.someProperty>=45 Or t.Consignment.Weight! = Convert(5000)).

当然,我需要上面的整个表达式,而不需要 "Convert"。因为这个 "Convert" 不会相应地从表中获取数据。

如有任何帮助,我们将不胜感激!剩下的应该做什么?我已经知道转换,但这会使整个表达式变得无用,因为它不会因为不必要的 "Convert"

而投影记录

已添加

   Expression NotEqual<T>(Expression PropertyType, ConstantExpression a_Constant, ParameterExpression parameter)
   {
    if(IsNullableType(Property.Type) &&!IsNullableType(a_Constant.Type))
    {
      var converted = a_Constant.Type != Property.Type ?  (Expression)Expression.Convert(a_Constant, Property.Type): (Expression)a_Constant;

     // here above statement returns (Convert(50000)) and all I want (50000), but i tried all combinitions from Expression in order to form this constant as expression, it always throws exception what I mentioned originally.

     var body = Expression.MakeBinary(ExpressionType.NotEqual, PropertyType,  converted);

    //MakeBinary statement returns {(t.Weight != Convert(5000000))} but I    need {(t.Weight != 5000000)}

     var expr = Expression.Lambda<Func<T, bool>>(body, parameter);
     return expr;
    }
  }

代码:

public class Consignment
{
    public float? Weight { get; set; }
}    

public static class GenericQueryExpressionBuilder
{        
    private static Expression NotEqual<T>(Expression memberExpression, ConstantExpression a_Constant, ParameterExpression parameter)
    {
        ConstantExpression constantExpression = null;

        if (IsNullableType(memberExpression.Type) && !IsNullableType(a_Constant.Type))
        {                
             //var converted = a_Constant.Type != memberExpression.Type ? (Expression)Expression.Convert(a_Constant, memberExpression.Type) : (Expression)a_Constant;

           Expression constantExp =  Expression.Property(a_Constant,typeof(T),"Weight");

        **// above statement throws exception I commented.**

            var body = Expression.MakeBinary(ExpressionType.NotEqual, memberExpression, converted);

            //here I want "t=>(t.Weight!=5000.0) INSTEAD of t=>(t.Weight!=Convert(5000.0))"

            var expr = Expression.Lambda<Func<T, bool>>(body, parameter);
            return expr;
        }

        else if (!IsNullableType(memberExpression.Type) && IsNullableType(a_Constant.Type))
            memberExpression = Expression.Convert(memberExpression, a_Constant.Type);

        return Expression.NotEqual(memberExpression, constantExpression);
    }

    static bool IsNullableType(Type t)
    {
        return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
    }        

    private static Expression GetExpression<T>(ParameterExpression param, string a_strPropertyName, string Operator, object Value)
    {            
        MemberExpression member = Expression.Property(param, a_strPropertyName);
        ConstantExpression constant = Expression.Constant(Value);

        try
        {               
           return GenericQueryExpressionBuilder.NotEqual<T>(member, constant, param);             

        }
        catch (InvalidOperationException)
        {
            return null;
        }

        return null;
    }

    public static Expression<Func<T, bool>> GetExpression<T>(Consignment consignment)
    {
        Expression expression = null;

        var parameter = Expression.Parameter(typeof(T), "t");

        string PropertyName = "Weight";
        string Operation = "NotEqual";
        object Value = consignment.Weight;

        expression = GenericQueryExpressionBuilder.GetExpression<T>(parameter, PropertyName, Operation, Value);
        return Expression.Lambda<Func<T, bool>>(expression, parameter);
    }
}
class Program
{
    static void Main(string[] args)
    {


        Consignment consignment = new Consignment();
        consignment.Weight = 50000.0f;

        var deleg = GenericQueryExpressionBuilder.GetExpression<Consignment>(consignment).Compile();            

    }
   }

这是一个简短但完整的示例,展示了如何构建 c => c.Weight.HasValue && c.Weight.Value != 5000f 表达式树。我从问题中删除了很多不相关的代码:

using System;
using System.Linq.Expressions;

public class Consignment
{
    public float? Weight { get; set; }
}    

public class Test
{        
    private static Expression NotEqual(Expression memberExpression,
                                       ConstantExpression constantToCompare)
    {
        // Other cases removed, for simplicity. This answer only demonstrates
        // how to handle c => c.Weight != 5000f.
        var hasValueExpression = Expression.Property(memberExpression, "HasValue");
        var valueExpression = Expression.Property(memberExpression, "Value");
        var notEqual = Expression.NotEqual(valueExpression, constantToCompare);
        return Expression.AndAlso(hasValueExpression, notEqual);
    }

    static void Main(string[] args)
    {
        Consignment consignment = new Consignment();
        consignment.Weight = 50000.0f;

        var parameter = Expression.Parameter(typeof(Consignment), "c");
        var weight = Expression.Property(parameter, "Weight");
        var constant = Expression.Constant(5000f, typeof(float));
        var weightNotEqualExpression = NotEqual(weight, constant);
        var lambda = Expression.Lambda<Func<Consignment, bool>>
            (weightNotEqualExpression, parameter);
        Console.WriteLine(lambda);
    }
}