7
votes

Comment gérer "Tous les chemins de code ne renvoient pas une valeur" lorsque la logique de la fonction assure un retour

Je suppose que le moyen le plus simple d'expliquer est d'un exemple de contreveillé: xxx

Ce code ne compilera pas et donne l'erreur "Tous les chemins de code ne renvoient pas de valeur", tandis que nous les humains peut clairement voir que ça fait. Je comprends pourquoi. Ma question est ce qui devrait être fait pour remédier à la situation. Cela pourrait être quelque chose comme ceci: xxx

mais tout semble plutôt idiot. Y a-t-il une meilleure façon? Encore une fois, ce code est un exemple artificiel (et peut être réduit à retour 0 ). Mon code actuel est vasif et complexe, mais logique logiquement (par preuve mathématique) renvoie une valeur avant d'essayer de quitter.


3 commentaires

Notez que si vous déclarez B en tant que variable locale const Const ( const bool b = true; ), il compile tout simplement bien


Si votre méthode est si «massive et complexe», vous devez probablement le refroidir. Quel espoir le prochain programmateur humain aurait-il si un compilateur l'abandonne?


github.com/coder0xff/parlex/blob/master/ide/nfa. CS basé sur l'algorithme Kameda-Weiner dans "Sur la minimisation de l'état d'automates finis non déterministes". Ce truc n'est pas pour les programmeurs humains.


6 Réponses :


8
votes

L'analyse de flux de code C # est limitée et que votre échantillon fait apparaître des cas où tous les chemins reviennent, mais le compilateur ne peut pas le détecter. Jeter une exception est un recours acceptable dans ces circonstances.

Je n'utiliserais pas de retour d'une valeur par défaut pour corriger cette erreur. Vous opérez sous l'hypothèse que la ligne n'est jamais frappée contre les conseils du compilateur. Considérez une seconde que votre analyse est fausse et que l'exécution peut passer à la fin de la méthode. Si vous retournez une valeur par défaut, vous n'aurez aucune indication du problème. La méthode va simplement renvoyer des données mauvaises. Lancer une exception fera très évident qu'il y a un problème.

Cependant, dans ces cas, ma préférence consiste simplement à réécrire le code de telle sorte que le compilateur puisse voir que tous les chemins se terminent. En général, j'ai constaté que si la méthode est si complexe que le compilateur ne puisse pas le suivre, le gars qui choisit le code après que je ne puisse pas le suivre non plus.


3 commentaires

Le refactoring est également mon premier instinct. Malheureusement, dans ce cas (minimisation de la NFA), le problème est intraitable (dans le sens mathématique) et cela ne peut pas vraiment être fait. Je passe à travers une boucle, testant certaines conditions, dont je sais au moins une autre sera utilisée à la suite du résultat.


J'ai décidé, après quelques jours, j'aime mieux votre réponse et que je vous ai commutée. Je veux demander cependant quelle exception dois-je jeter? Je pourrais faire un THEASSOUSSMADEALEBOUTTHISPOGRAMSLOGICAREINCORRECTECTECTIO N , mais comme je l'ai dit, il semble tout simplement un peu idiot.


@Brent personnellement, je voudrais simplement utiliser system.exception mais ajouter dans un message très spécifique sur ce qui s'est mal passé.



1
votes

Le compilateur n'effectue pas de processus mathématiques complexes pour vous assurer de retourner une valeur, c'est une bête relativement stupide à cet égard.

Si vous êtes certain de vos hypothèses, ajoutez simplement retour 0; à la fin avec un commentaire indiquant la réalité, qu'elle ne sera jamais atteinte.

Bien sûr, n'importe quel code où il peut être garanti que l'état final sera vrai peut simplement avoir la condition supprimée, comme vous l'avez déjà indiqué. C'est mathématiquement vrai, même pour des cas complexes. Donc, vous pouvez refroidir votre code pour le prendre en compte sans un retour superflu.


4 commentaires

Consultez mon commentaire à la réponse de Jaredpar. Cependant, je pense que je vais devoir être d'accord avec vous. Un retour null; // Ce code est inaccessible semble être la meilleure chose.


Paxdiablo a raison, la bonne façon est ce qu'il a dit. Mais si cela vous rendra plus heureux;), vous pouvez définir Minnfa à l'extérieur de la fourchette, puis rompre si, et revenez enfin à Minnfa après la franchise. (Basé sur votre code ici: github.com/coder0xff/parlex/blob /master/ide/nfa.cs )


@MNZ Pouvez-vous clarifier comment cela serait fait? Pour autant que je sache, cela équivaut à décider du problème d'arrêt. En outre, sur la base de l'approche «Minnfa» que vous décrivez, je devrais toujours initialiser Minnfa à NULL, car le compilateur décide toujours que le forach peut ne pas définir sa valeur.


@Brent sûr, il doit être initialisé. Mais cela diminuera la lisibilité du code, IMHO. Donc, je pense que l'approche n'est pas si bonne dans la pratique. :)



0
votes

Il y a généralement quelques classes de programmeurs:

  1. ils qui rentrent partout. li>
  2. Ils ne rentrent que à la fin d'une fonction / méthode. li> ol>

    première approche: p> xxx pré>

    Je préfère généralement la deuxième approche car il est plus facile de voir rapidement où une fonction / méthode revient. P>

    public static int Fail() {
      var b = true;
      var returnValue = 1:
      if (b)
        returnValue = 0;
    
      return returnValue;
    }
    


0 commentaires

1
votes

Je pense que votre approche actuelle est correcte. Renvoyer une valeur par défaut à la fin de la méthode est risquée, car s'il y a un flux dans votre logique, cette instruction pourrait être atteinte, ce qui pourrait avoir des conséquences inattendues. Si vous lancez une exception, cela vous donne une chance de détecter l'erreur.


0 commentaires

0
votes

réponse vraiment tardive, mais je peux imaginer un scénario dans lequel la fonction ne saura pas quoi retourner:

1) exécutoire étape par étape à l'aide du débogueur

2) étape sur var b = true;

3) Lorsque si (b) { est atteint, mettez b = faux dans la montre. Il va tous les deux retourner false et attribuer b = faux

4) étape sur (sur si )

5) La fin de la fonction est atteinte, aucun retour n'est là

Dans cette perspective, retour est clairement nécessaire.


0 commentaires

0
votes

J'avais du code comme celui-ci et j'ai réparé de cette façon. En regardant votre exemple:

public static int Fail() {
    var b = true;
    if (!b) {
        throw new ApplicationException("This code is unreachable... but here we are.");
    }
    return 0;
}


2 commentaires

Comme d'autres réponses mentionnent, une valeur «par défaut» n'est pas propre. Si la logique de la fonction change, vous pouvez retourner soudainement une magie 0.


Ce n'est pas une valeur "par défaut". J'ai pris l'extrait de code de l'exemple original. Ce code supprimera les erreurs "Tous les chemins de code renvoyer une valeur" de l'IDE, qui est la question initiale. Nous pourrions dire qu'au lieu de "retourner 0;" Nous avons plutôt un code qui dépend de la variable "B" étant vrai.