Comment obtenir des valeurs (champs) Expression for Nullable sans convertir Expression.Convert en C #?

c# expression-trees lambda linq-expressions

Question

Je traite du scanario des types Nullable lors de la formation d'expressions de requête dynamiques. Ces expressions permettraient d'extraire les données filtrées de toutes les tables SQL (en interface avec les classes Code First utilisant EF).

J'ai un objet normal (par exemple, un envoi opérant sur plusieurs propriétés avec des propriétés nullables).

Ma formation d'expression va bien jusqu'à ce que je rencontre des types Nullables. Sur ces nullables, je reçois

L'opérateur binaire NotEqual n'est pas défini pour les types 'System.Nullable`1 [System.Single]' et 'System.Single'.

Pour supprimer cette exception, j'utilise toutes les approches concernant la conversion postées sur différents threads.

Invocation d'expressions lambda dans les arbres d'expression

Essayer de filtrer sur un type Nullable en utilisant des arbres d'expression

Ils génèrent tous des expressions avec le mot ajouté "Convert" (c'est-à-dire Convert (someValue)) et, par conséquent, j'ai toujours une expression.

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

Bien sûr, j'ai besoin de toute l'expression ci-dessus SANS "Convertir". Parce que ce "Convertir" ne récupérera pas les données des tables en conséquence.

Toute aide serait grandement appréciée! Que devrait-il rester à faire? Je connais déjà la conversion, mais cela rend toute l'expression inutile, car elle ne projettera pas les enregistrements à cause de "Convertir" inutile

Ajoutée

   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;
    }
  }

Code:

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();            

    }
   }

Réponse acceptée

Voici un exemple court mais complet montrant comment construire l'arborescence d'expression c => c.Weight.HasValue && c.Weight.Value != 5000f . J'ai retiré beaucoup de code non pertinent de la question:

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);
    }
}


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow