Como verificar se duas Expressões <Func > são as mesmas

É possível descobrir se duas expressões são iguais?

Como dadas as quatro expressões a seguir:

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

Então, pelo menos , podemos ver isso:

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

Mas posso fazer alguma coisa para descobrir isso no meu código?

Deu uma olhada na biblioteca msdn, onde diz que

Equals : Determina se o object especificado é igual ao Object atual. (Herdado de Object .)

o que eu acho que significa que pelo menos a class Expression não substituiu o método equals para se tornar Equatable? Então, como você faria isso? Ou estou pedindo muito aqui? : p

Você pode dar uma olhada no tipo ExpressionEqualityComparer que é usado dentro do Linq para db4o . Ele implementa a interface IEqualityComparer , portanto, é utilizável para collections genéricas, bem como para um uso independente.

Ele usa o tipo ExpressionComparison para comparar duas expressões para igualdade e HashCodeCalculation , para calcular um código hash de uma expressão.

Tudo envolve visitar a tree de expressão, por isso pode ser bastante caro se você fizer isso repetidamente, mas também pode ser bastante útil.

O código está disponível sob a GPL ou o dOCL

Por exemplo, aqui está o seu teste:

 using System; using System.Linq.Expressions; using Db4objects.Db4o.Linq.Expressions; class Test { static void Main () { Expression> a = x => false; Expression> b = x => false; Expression> c = x => true; Expression> d = x => x == 5; Func eq = ExpressionEqualityComparer.Instance.Equals; Console.WriteLine (eq (a, b)); Console.WriteLine (eq (a, c)); Console.WriteLine (eq (a, d)); } } 

E realmente imprime Verdadeiro, Falso, Falso.

Como uma resposta preguiçosa, você pode verificar ToString() – deve pelo menos indicar onde eles são claramente diferentes (embora inclua o var-name lá, então isso teria que ser o mesmo).

Para verificar a equivalência com precisão … muito mais difícil – muito trabalho, em muitos tipos diferentes de nós.

Parece-me que isso pode ser difícil de fazer, exceto no mais simples dos casos.

Por exemplo:

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

Tecnicamente, estes são iguais, mas como poderia ser determinado sem avaliar o IEnuemrable retornado em cada expressão?