Come ottenere Expression per valori Nullable (campi) senza la conversione da Expression.Convert in C #?

c# expression-trees lambda linq-expressions

Domanda

Mi occupo dello scanario dei tipi Nullable durante la formazione di espressioni di query dinamiche. Queste espressioni prelevano i dati filtrati da qualsiasi tabella SQL (interfaccia con le classi Code First usando EF).

Ho un oggetto normale (ad es. La spedizione che opera su più proprietà insieme alle proprietà Nullable).

La mia formazione espressiva va bene fino a quando incontrerò alcuni tipi di Nullable. Su questi nullable, sto ottenendo

L'operatore binario NotEqual non è definito per i tipi 'System.Nullable`1 [System.Single]' e 'System.Single'.

Per rimuovere questa eccezione, sto utilizzando tutti gli appraoches relativi alla conversione pubblicati su thread diversi.

Richiamo di espressioni lambda negli alberi di espressione

Cercando di filtrare su un tipo Nullable usando Expression Trees

Tutti questi stanno generando espressioni con la parola aggiunta "Convert" (ad esempio Convert (someValue)) e nel risultato ho sempre un'espressione

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

Ovviamente ho bisogno dell'intera espressione sopra SENZA "Converti". Perché questo "Converti" non recupera i dati dalle tabelle di conseguenza.

Qualsiasi aiuto sarebbe molto apprezzato! Cosa dovrebbe fare? Conosco già la conversione, ma questo rende l'intera espressione inutile, perché non proietterà i record a causa di "Converti" inutili

aggiunto

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

Codice:

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

    }
   }

Risposta accettata

Ecco un breve ma completo esempio che mostra come costruire l'albero delle espressioni c => c.Weight.HasValue && c.Weight.Value != 5000f . Ho rimosso un sacco di codice irrilevante dalla domanda:

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


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché