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 aet bsont définitivement attribués. Même avec les bizarreries que vous pouvez créer dans le typage dynamique, je m'attendrais à n'évaluer a <= bqu'après avoir évalué les deux TryParseappels.
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 && Cqui évalue Aet Cmais 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 dynamicest 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 vun 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 bune 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 à bavant 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 boolopérandes. Je vais essayer de m'assurer que cela est corrigé pour la prochaine norme ECMA.
bqu'après avoir été affecté via unoutparamètre.