2009-03-23 18 views
39

È possibile sapere se due espressioni sono uguali?Come verificare se due espressioni <Func <T, bool>> sono uguali

Come dato i seguenti quattro espressioni:

 Expression<Func<int, bool>> a = x => false; 
     Expression<Func<int, bool>> b = x => false; 
     Expression<Func<int, bool>> c = x => true; 
     Expression<Func<int, bool>> d = x => x == 5; 

Poi, almeno si può vedere che:

  • a == b
  • a != c
  • a != d

Ma posso fare qualcosa per scoprirlo nel mio codice?

Ha preso una sbirciatina in MSDN Library, dove si dice che

Equals: determina se l'oggetto specificato è uguale alla corrente Object. (Ereditato da Object.)

che immagino significa che almeno la classe di espressione non ha overrided il metodo equals per diventare equatable? Quindi come lo faresti? O sto chiedendo troppo qui? : p

+0

Se c'è un 'MemberInfo' coinvolto lì, intendo qualche metodo, proprietà di campo, quindi è possibile ottenere il membroinfo per primo e calcolare il suo hash – nawfal

risposta

32

È possibile dare un'occhiata al tipo ExpressionEqualityComparer utilizzato all'interno di Linq to db4o. Implementa l'interfaccia IEqualityComparer <T>, quindi è utilizzabile per raccolte generiche, nonché per un utilizzo standalone.

Utilizza il tipo ExpressionComparison per confrontare due espressioni per l'uguaglianza e HashCodeCalculation per calcolare un codice hash da un'espressione.

Tutto ciò comporta visitare l'albero delle espressioni, quindi può essere piuttosto costoso se lo si fa ripetutamente, ma può anche essere abbastanza utile.

Il codice è disponibile sotto licenza GPL o dOCL

Per esempio, ecco il test:

using System; 
using System.Linq.Expressions; 

using Db4objects.Db4o.Linq.Expressions; 

class Test { 

    static void Main() 
    { 
     Expression<Func<int, bool>> a = x => false; 
     Expression<Func<int, bool>> b = x => false; 
     Expression<Func<int, bool>> c = x => true; 
     Expression<Func<int, bool>> d = x => x == 5; 

     Func<Expression, Expression, bool> eq = 
      ExpressionEqualityComparer.Instance.Equals; 

     Console.WriteLine (eq (a, b)); 
     Console.WriteLine (eq (a, c)); 
     Console.WriteLine (eq (a, d)); 
    } 
} 

Ed in effetti stampa True, False, False.

+0

Sembrava promettente, ma quali sono questi ExpressionComparison (a, b). AreEqual e HashCodeCalculation (espressione) .HashCode? – Svish

+1

È possibile sfogliare l'implementazione, si trovano nella stessa cartella. –

+0

Penso che proverò a trovare un altro modo per risolvere quello che sto cercando di capire: p Ma la tua risposta sembra fornire una soluzione funzionante, quindi la contrassegnerò come Accepted =) – Svish

4

Mi sembra che questo potrebbe essere difficile da fare, tranne nei casi più semplici.

Ad esempio:

var numbers1 = Enumerable.Range(1, 20); 
Expression<Func<int, IEnumerable<int>>> a = x => numbers1; 
var numbers2 = Enumerable.Range(1, 20); 
Expression<Func<int, IEnumerable<int>>> b = x => numbers2; 

Tecnicamente, questi sono uguali, ma come potrebbe essere determinato senza valutare IEnuemrable restituiti in ogni espressione?

+1

Chiedo a voi ragazzi qui: p hehe. Ma sì, posso vedere il problema .. ma posso anche ... non vederlo. Perchè come hai detto tu, tecnicamente quelli sono di fatto uguali. E, almeno io, penserei che un albero di espressioni dovrebbe essere paragonabile a un altro albero di espressioni basato sui loro nodi e tipi di dati. – Svish

+4

Nel tuo esempio, penso che potrei aver considerato queste espressioni non uguali, poiché contengono un riferimento a un oggetto che non è lo stesso ... – Svish

+0

numeri1 o numeri2 saranno serializzati come nodo ConstantExpression, i cui valori non saranno uguali . –

11

Come risposta lenta, è possibile controllare ToString() - dovrebbe almeno indicare dove sono chiaramente diversi (anche se includerà il nome var in là, in modo che dovrebbe essere lo stesso).

Per il controllo dell'equivalenza con precisione ... molto più difficile - un sacco di lavoro, su molti tipi di nodi diversi.

+0

Lol, ora potrebbe funzionare in qualche modo ...: D – Svish

+2

No, non tutte le espressioni hanno un usab rappresentazione di stringa. Converti ad esempio non indica in quali tipi viene convertito. –

+2

Esattamente - ho detto che avrebbe trovato risposte ovviamente sbagliate, ma questo è tutto. Avresti bisogno di camminare correttamente sull'albero, controllando gli operatori effettivi usati, ecc. Per fare un lavoro completo. –

Problemi correlati