2013-08-24 6 views
6

Ich nehme an der einfachste Weg, durch ein konstruiertes Beispiel zu erklären ist:Wie handhaben „nicht alle Codepfade einen Wert zurückgeben“, wenn die Logik der Funktion eine Rückkehr nicht gewährleistet

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

Dieser Code wird nicht kompiliert und gibt den Fehler "nicht alle Codepfade geben einen Wert zurück", während wir Menschen klar sehen können, dass dies der Fall ist. Ich verstehe warum. Meine Frage ist, was getan werden sollte, um die Situation zu verbessern. Es könnte so etwas sein:

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

Aber alles scheint nur ziemlich albern. Gibt es einen besseren Weg? Auch dieser Code ist ein künstliches Beispiel (und kann auf return 0 reduziert werden). Mein tatsächlicher Code ist massiv und komplex, liefert aber logischerweise (durch mathematischen Beweis) einen Wert, bevor er versucht, zu beenden.

+0

Beachten Sie, dass, wenn Sie b als eine 'const' lokale Variable deklarieren ('const bool b = true;'), kompiliert es einfach –

+1

Wenn Ihre Methode so "massiv und komplex" ist, sollten Sie sie wahrscheinlich umgestalten. Welche Hoffnung hätte der nächste menschliche Programmierer, wenn ein Compiler aufgibt? – lesscode

+1

https://github.com/coder0xff/parlex/blob/master/IDE/Nfa.cs basiert auf dem Kameda-Weiner-Algorithmus in "Über die Zustandsminimierung von nichtdeterministischen endlichen Automaten". Dieses Zeug ist nicht für menschliche Programmierer. – Brent

Antwort

8

C# -Code-Flow-Analyse ist begrenzt und wie Ihr Beispiel zeigt, gibt es Fälle, in denen alle Pfade zurückgeben, aber der Compiler kann es nicht erkennen. Eine Ausnahmeregelung ist unter diesen Umständen ein akzeptables Mittel.

Ich würde keine Rückgabe eines Standardwerts verwenden, um diesen Fehler zu beheben. Sie arbeiten unter der Annahme, dass die Zeile nie gegen den Rat des Compilers getroffen wird. Überlegen Sie für eine Sekunde, dass Ihre Analyse falsch ist und die Ausführung bis zum Ende der Methode fortgesetzt werden kann. Wenn Sie einen Standardwert zurückgeben, haben Sie keine Anzeichen für das Problem. Die Methode gibt nur schlechte Daten zurück. Durch das Auslösen einer Ausnahme wird deutlich, dass ein Problem vorliegt.

In diesen Fällen ist es jedoch meine Vorliebe, den Code einfach neu zu schreiben, so dass der Compiler sehen kann, dass alle Pfade enden. Im Allgemeinen habe ich festgestellt, dass, wenn die Methode so komplex ist, dass der Compiler nicht folgen kann, der Typ, der den Code nach mir aufnimmt, auch nicht in der Lage sein wird, ihm zu folgen.

+0

Refactoring ist auch mein erster Instinkt. Leider ist in diesem Fall (NFA-Minimierung) das Problem (im mathematischen Sinne) unlösbar und dies kann nicht wirklich durchgeführt werden. Ich gehe eine Schleife durch und teste einige Bedingungen, von denen ich weiß, dass mindestens einer als Ergebnis verwendet wird. – Brent

+0

Ich habe entschieden, nach ein paar Tagen, dass ich deine Antwort am besten mag, und wechselte es zu dir. Ich möchte allerdings fragen, welche Ausnahme ich werfe? Ich könnte eine 'TheAssumptionsMadeAboutThisProgramsLogicAreIncorrectException' machen, aber wie gesagt, es scheint alles nur ein bisschen albern. – Brent

+0

@Brent persönlich Ich würde nur "System.Exception" verwenden, aber fügen Sie eine sehr spezifische Nachricht über was schief gelaufen ist. – JaredPar

1

Der Compiler führt keine komplexen mathematischen Prozesse durch, um sicherzustellen, dass Sie einen Wert zurückgeben, es ist in dieser Hinsicht ein relativ dummes Biest.

Wenn Sie sich Ihrer Annahmen sicher sind, fügen Sie einfach am Ende return 0; mit einem Kommentar hinzu, der die Realität angibt, dass sie niemals erreicht wird.

Natürlich kann jeder Code, wo es garantiert werden kann, die endgültige Bedingung wahr sein, kann nur die Bedingung entfernt haben, wie Sie bereits festgestellt haben. Das ist mathematisch auch für komplexe Fälle zutreffend. Sie könnten also Ihren Code umgestalten, um das zu berücksichtigen ohne eine überflüssige Rückkehr.

+0

Siehe meinen Kommentar zu JaredPars Antwort. Ich denke jedoch, dass ich dir zustimmen muss. A 'zurück null; // Dieser Code ist unerreichbar, scheint das Beste zu sein. – Brent

+0

paxdiablo ist richtig, der richtige Weg ist, was er gesagt hat. Aber wenn es dich glücklicher macht;), kannst du minNfa außerhalb von foreach definieren, dann einfach einbrechen wenn und schließlich minNfa nach fileach zurückgeben. (Basierend auf Ihrem Code hier: https://github.com/coder0xff/parlex/blob/master/IDE/Nfa.cs) – MNZ

+0

@MNZ können Sie klären, wie das getan würde? Soweit ich das beurteilen kann, ist dies gleichbedeutend mit der Entscheidung für das Anhalteproblem. Auf der Grundlage des von Ihnen beschriebenen Ansatzes "minNfa" müsste ich außerdem minNfa auf null initialisieren, da der Compiler immer noch entscheidet, dass der foreach seinen Wert nicht setzen kann. – Brent

0

Es gibt in der Regel ein paar Klassen von Programmierern:

  1. Sie die ganzen zurückzukehren.
  2. Sie, die nur am Ende einer Funktion/Methode zurückkehren.

Erster Ansatz:

public static int Fail() { 
    var b = true; 
    if (b) 
    return 0; 

    return 1; 
} 

Ich ziehe normalerweise die zweite Ansatz, da es einfacher ist, schnell zu sehen, wo eine Funktion/Methode zurückgibt.

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

    return returnValue; 
} 
1

Ich denke, Ihre aktuelle Vorgehensweise ist richtig. Die Rückgabe eines Standardwerts am Ende der Methode ist riskant, da bei einem Fluss in Ihrer Logik diese Anweisung erreicht werden könnte, was unbeabsichtigte Konsequenzen haben könnte.Wenn Sie eine Ausnahme auslösen, können Sie den Fehler erkennen.

0

sehr spät Antwort, aber ich kann ein Szenario vorstellen, in dem die Funktion nicht wissen, was zurückzukehren:

1) Führen Sie Schritt für Schritt den Debugger

2) Schritt über var b = true;

mit

3) Wenn if (b) { erreicht ist, setzen Sie b = false in die Uhr. Es wird sowohl false zurückkehren und weist b = false

4) Schritt über (über if)

5) Ende der Funktion erreicht ist, keine Rückkehr gibt es

Aus dieser Perspektive ist return dies unbedingt erforderlich ist.

Verwandte Themen