Perché è necessaria una conversione in Expression Trees

c# entity-framework expression-trees

Domanda

Da questa domanda che ho chiesto 5 minuti fa, è chiaro che il seguente codice genera un'eccezione, affermando che

Eccezione non gestita: System.InvalidOperationException: l'operatore binario Equal non è definito per i tipi 'System.Nullable`1 [System.Int32]' e 'System.Int32'.

Codice

public static void GetResultCollection<T>() {
        AccrualTrackingEntities db = new AccrualTrackingEntities();
        var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));

        int? ItemTypeValue = 1;

        var param = Expression.Parameter(typeof(T));

        var lambda = Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(param, "ProcInstId"),
                Expression.Constant(ItemTypeValue)),
            param);

        var list = result.Where(lambda).ToList();
    }

Questo codice, tuttavia, con il tipo esplicitamente elencato in Expression.Constant funziona

class Program {
    public static void GetResultCollection<T>() {
        AccrualTrackingEntities db = new AccrualTrackingEntities();
        var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));

        int? ItemTypeValue = 1;

        var param = Expression.Parameter(typeof(T));

        var lambda = Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(param, "ProcInstId"),
                Expression.Constant(ItemTypeValue, typeof(int?))),
            param);

        var list = result.Where(lambda).ToList();
    }

La domanda è: perché Expression.Constant non è in grado di convertire implicitamente da int? a ... int?

Risposta accettata

Gli alberi di espressione funzionano a un livello inferiore rispetto al normale codice sorgente: è possibile pensare che funzionino a livello dell'output del compilatore anziché dell'input . Quindi, mentre c'è una conversione implicita da int a int? in C #, quella conversione deve essere rappresentata in IL ogni volta che il compilatore la usa per un metodo normale ... quindi deve anche essere presente in una rappresentazione ad albero di espressioni.

Detto questo, il tuo esempio non è chiaro, dato che stai provando a usare un int (cioè ItemTypeValue.Value ) come valore per un int? costante, e non sappiamo quale sia il tipo di proprietà ItemType .

Un breve ma completo esempio di ciò che ti aspetteresti di lavorare sarebbe davvero d'aiuto.

EDIT: Ok, penso di essere con te ora. Il problema è che se usi

int? foo = 1;
Expression.Constant(foo);

quindi chiama Expression.Constant(object) che contiene il valore di foo . A quel punto, Expression.Constant non può dire che era originariamente un int? , perché ora è un int inscatolato. Questo è solo il modo in cui funziona la boxe .NET:

int? foo = 1;
object o = foo;
Console.WriteLine(o.GetType()); // Prints System.Int32

Quel sovraccarico di Expression.Constant determina il tipo generale dell'espressione dal valore che è stato dato - quindi crea un'espressione int , mentre vuoi veramente un int? espressione.

Per mantenere correttamente le informazioni sul tipo, è necessario utilizzare il sovraccarico che consente di specificare il tipo:

int? foo = 1;
Expression.Constant(foo, typeof(int?));

Non è ancora del tutto chiaro dalla tua domanda quale codice funzioni e quale no, ma spero che possa aiutarti ...



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é