Qu'est-ce qui cause ce problème?
Cela ressemble à un bogue du compilateur. Du moins, ça l'a fait. Bien que les expressions decimal.TryParse(v, out a)
et decimal.TryParse(v, out b)
soient évaluées dynamiquement, je m'attendais à ce que le compilateur comprenne encore qu'au moment où il atteint a <= b
, les deux a
et b
sont définitivement attribués. Même avec les bizarreries que vous pouvez créer dans le typage dynamique, je m'attendrais à n'évaluer a <= b
qu'après avoir évalué les deux TryParse
appels.
Cependant, il s'avère que grâce à l'opérateur et à la conversion délicate, il est tout à fait possible d'avoir une expression A && B && C
qui évalue A
et C
mais pas B
- si vous êtes assez rusé. Voir le rapport de bogue de Roslyn pour l'exemple ingénieux de Neal Gafter.
Faire ce travail dynamic
est encore plus difficile - la sémantique impliquée lorsque les opérandes sont dynamiques est plus difficile à décrire, car pour effectuer une résolution de surcharge, vous devez évaluer les opérandes pour savoir quels types sont impliqués, ce qui peut être contre-intuitif. Cependant, encore une fois Neal est venu avec un exemple qui montre que l'erreur du compilateur est nécessaire ... ce n'est pas un bug, il est un bug fix . D'énormes félicitations à Neal pour l'avoir prouvé.
Est-il possible de le réparer via les paramètres du compilateur?
Non, mais il existe des alternatives qui évitent l'erreur.
Premièrement, vous pouvez l'empêcher d'être dynamique - si vous savez que vous n'utiliserez jamais que des chaînes, vous pouvez alors utiliser IEnumerable<string>
ou donner à la variable range v
un type de string
(ie from string v in array
). Ce serait mon option préférée.
Si vous avez vraiment besoin de le garder dynamique, donnez simplement b
une valeur pour commencer:
decimal a, b = 0m;
Cela ne fera aucun mal - nous savons qu'en fait votre évaluation dynamique ne fera rien de fou, vous finirez donc par attribuer une valeur à b
avant de l'utiliser, ce qui rendra la valeur initiale non pertinente.
De plus, il semble que l'ajout de parenthèses fonctionne aussi:
where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)
Cela change le moment où les différentes parties de la résolution de surcharge sont déclenchées et rend le compilateur heureux.
Il reste un problème à résoudre - les règles de la spécification sur l'affectation définitive avec l' &&
opérateur doivent être clarifiées pour indiquer qu'elles ne s'appliquent que lorsque l' &&
opérateur est utilisé dans son implémentation "régulière" avec deux bool
opérandes. Je vais essayer de m'assurer que cela est corrigé pour la prochaine norme ECMA.
b
qu'après avoir été affecté via unout
paramètre.