11
votes

Comment les expressions LINQ déterminent-elles l'égalité?

J'envisage d'utiliser une expression LINQ comme clé dans un dictionnaire. Cependant, je suis préoccupé par le fait que je reçois des résultats étranges, car je ne sais pas comment l'égalité est déterminée par les expressions Linq.

Une classe dérivée-t-elle de l'expression comparer la valeur égalité ou l'égalité de référence? Ou en d'autres termes, xxx


4 commentaires

L'avez-vous essayé? LINQPAD est idéal pour tester de petits extraits de code.


La question n'est pas basée sur une prémisse correcte; Un dictionnaire <,> est pas Utilisez l'opérateur == pour l'égalité des clés.


Dans ce cas, vous n'avez qu'ils n'ont ni la même référence ni la même valeur.


@Rangoric me semble que leur valeur est la même (même s'ils utilisent la sémantique d'égalité de référence): l'arborescence d'expression générée aura des objets avec les mêmes types et avec les mêmes valeurs. Même leur représentation de chaîne sera la même.


3 Réponses :


11
votes

Votre test se compare expressions em>. Les expressions elles-mêmes n'offrent que l'égalité de référence; Votre test montrera probablement «faux». À la joue pour Sémantic em> l'égalité dont vous aurez besoin de faire beaucoup de travail, par exemple - sont les suivants:

y => 123


10 commentaires

Non, le nom de la paramètre-expression serait différent. Mais je reçois ta dérive. Je pense que le comportement devrait être que mes expressions renvoient true et que votre expression reviendrait fausse, car une implémentation pourrait dépendre du nom du paramètre.


@smartcaveman, même permettant des changements «innocents» comme celui-ci, je pense que ce serait une véritable lutte de le faire dans le cas général.


@smartcaveman: Si vous ne voulez pas que l'égalité sémantique comme Marc a montré et que tout soit exactement égal, y compris les noms de paramètres, vous pouvez écrire votre propre expressionniste pour la comparaison.


@Marc, Yup, je suis d'accord avec toi. J'étais juste un peu en espérant que c'était déjà cuit de là pour moi.


@Martinho @smartcaveman - en effet; Un visiteur complet est beaucoup de travail, surtout en 4.0


@MARC Savez-vous que des exemples de tels "visiteurs complets" existent librement disponible?


@Cottsak - On est intégré à .NET 4.0: < Code> Expressionnel - Si vous clarifiez ce que vous voulez faire, je pourrais peut-être être plus précis


Oh wow. Je veux simplement créer une fonction qui renvoie Bool si une expression > est égale à une autre. Égal dans la sémantique syntaxique du sens de l'arbre d'expression. C'est pour mes tests d'unité. Je vérifie que le code du bâtiment d'expression dynamique fonctionne correctement.


@Cottsak - C'est assez difficile à faire de manière robuste. J'ai dépensé d'énormes quantités d'expression, et personnellement, j'essaierais d'éviter que l'exigence - c'est fragile et délicate


@Marc comme je l'ai deviné. J'essaie également de la saisir en écrivant des tests qui affirment des éléments assortis de source moquée et d'inégalement des éléments de la même source moquée. Ensuite, affirmant les mêmes correspondances et non-correspondances de la source avec les expressions générées appliquées et mandater les mêmes résultats pour la simulation que les expressions générées. Pensez-vous que cela est raisonnable ou y a-t-il un moyen beaucoup plus simple de rencontrer à mi-chemin entre dire (a) des valeurs de branchement dans les versions attendues et réelles des versets (B) de l'ensemble du porc et de la construction du visiteur pour comparer l'égalité?



0
votes

Comparaison de deux objets qui ne sont pas des types de valeur (y compris une expression) avec == compare des références d'objet, elles ne seront donc pas égales. En tant que commentateur noté, cependant, un dictionnaire utiliserait égale et gethascode pour déterminer l'égalité, qui serait toujours par défaut de déterminer qu'ils n'étaient pas égaux.

Vous pouvez probablement créer une classe qui hérite system.linq.expression et remplacer gethascode et est égal à pour utiliser en quelque sorte le résultat, cependant, et utilisez-le comme la clé de votre dictionnaire.


11 commentaires

Votre première déclaration est trompeuse. Les types peuvent fournir des opérateurs statiques ==


En outre, il y a une myriade de classes d'expression; La ligne de sous-classe n'est pas une option ici.


Est-ce mieux? Ou parlez-vous de quelque chose que je ne comprends pas?


Ce n'est pas vrai avec tous les objets. (Considère la chaîne). Je ne pense pas que le dépassement obtiendrait la fonctionnalité que je veux, mais je pourrais créer une emballage qui évalue l'expression, mais comme le note Marc, cela entraînerait probablement plus de travail que la valeur.


@jamietre non, même une classe peut définir un opérateur ==. Si tel est le cas, le compilateur utilisera l'opérateur défini au lieu des referequaux.


Qu'entendez-vous par sous-classement, ce n'est pas une option? L'expression générique hérite d'une expression.


@smartCaveman - La chaîne est immuable. Je ne voulais vraiment pas entrer dans une valeur de référence et une chose de référence et tout cela, désolé, ma langue n'est pas précise.


@jamietre Oui, mais une expression Lambda la plus externe est composée de lots et de nombreux autres - vous pourriez être surpris de savoir combien d'objets sont dans les exemples simples ci-dessus.


Marc, je suis avec vous, mais je ne comprends toujours pas pourquoi vous ne pouviez pas utiliser une classe dérivée de cette manière. Si l'objet que vous créez pour ajouter au dictionnaire est de votre type dérivé, tandis que les expressions intérieures ne seraient pas, le dictionnaire ne demandera que l'objet le plus externe pour son code de hachage ne sera-t-il pas?


Oh ... OK, une minute de bricolage a révélé que l'expression générique est scellée.


Note finale: Bien que vous puissiez toujours accomplir cela en créant une classe d'emballage au lieu d'essayer d'hériter, nous sommes toujours confrontés au même problème que votre réponse: comment comparer les fonctions d'égalité. Donc, je suppose que cela n'a pas vraiment d'importance.



0
votes

Comme d'autres personnes ont noté, l'opérateur d'expression == utilise la vérification par défaut de référence "de référence" - "Sont-ils à la fois une référence au même endroit dans le tas?". Cela signifie que le code comme votre exemple reviendra probablement faux, car vos littéraux d'expression seront instanciés sous forme d'extensions différentes, quelle que soit toute égalité sémantique. Il existe des frustrations similaires avec l'utilisation de Lambdas en tant que gestionnaires d'événements: xxx

vérification de l'égalité sémantique est délicat. Dans ce cas particulier, vous pourrez peut-être visiter tous les nœuds de l'arborescence d'expression et comparer toutes les chaînes, types de valeur et références de méthodes pour déterminer qu'ils font la même chose. Cependant, par inspection, les deux lambdas de l'exemple suivant sont sémantiquement équivalents, mais vous auriez du mal à écrire une méthode pour la prouver: xxx


2 commentaires

Je pense que ces deux méthodes ne devraient pas être évaluées pour être égales. Mais connaissez-vous un moyen d'inspecter un corps de méthode?


Vous pouvez obtenir le corps de la méthode de manière réfléchie en obtenant une méthodeInfo pour la méthode en question. Il peut également y avoir un moyen de l'examiner à l'aide d'un avaluator (de l'IQToolkit); Je sais que LINQ2SQL et d'autres ormes avec des fournisseurs Linq semblent pouvoir convertir des méthodes d'extension définies par l'utilisateur, je ne sais tout simplement pas à quel point il serait facile de reproduire cela (probablement pas facile du tout).