5 Stimmen

Methode, die bedingte Rückgabe des aufrufenden Methode macht?

Ok, das könnte ein bisschen gehackt sein, aber haltet durch :) Der Hintergrund ist, dass ich es leid bin, Methoden zu sehen, die einen if-Statement enthalten, das die Einrückung für die gesamte Methode durcheinanderbringt, wie zum Beispiel:

public SomeClass DoStuff(string inputStr)
{
  SomeClass result =null;
  if (IsOpenFilter(inputStr))
  {
    ....
  }

  return result;
}

Also dachte ich mir, wäre es nicht toll, stattdessen so etwas zu tun:

public SomeClass DoStuff(string inputStr)
{
  Require(IsOpenFilter(inputStr),null);

  ....

  return result;
}

Dieser Fall könnte in irgendeiner Form von Code Contracts abgedeckt sein, wenn ja, bitte korrigiere mich :)

Die Idee ist, dass, wenn die Aussage nicht wahr ist, null zurückgegeben wird. Wenn es keinen Rückgabetyp für die Methode gäbe, würde es einfach sein: Require(IsOpenFilter(inputStr));

Also, ich denke, es gibt zwei Fragen, kann das irgendwie gemacht werden? Ich bin ratlos, wie man einen bedingten Rückgabewert von dem Aufruf einer Methode aus machen kann.

Die andere Frage ist, ob das eine gute Idee ist? Es ist etwas seltsam, die Sprache auf diese Weise zu "monkeypatchen", aber mir gefällt die Art und Weise, wie der Code aussieht. Es wäre noch sauberer, wenn es in Form eines Attributs über der Methode stehen könnte: [Require(IsOpenFilter(inputStr))]

5 Stimmen

Warum setzen Sie nicht einfach if (!IsOpenFilter(inputStr)) return null; am Anfang Ihrer Funktion?

0 Stimmen

Zustimmen! Das ist, was ich tun würde. Weil ich es hasse, ein If-Indent im Code-Block mitzunehmen.

2 Stimmen

Es steht im Konflikt mit meinen bevorzugten Formatierungsregeln in Visual Studio und fügt einen Zeilenumbruch hinzu, außerdem ist es meiner Meinung nach nicht so elegant :)

10voto

Jon Skeet Punkte 1325502

Ich stimme Anders zu: Kehren Sie die Bedingung um und kehren Sie frühzeitig zurück. "Einzelner Rückgabepunkt" war früher wertvoll, wenn Sie an diesem Rückgabepunkt explizit eine Menge Ressourcenbereinigung durchführen mussten; mit finally-Blöcken, using-Anweisungen und Garbage Collection ist es meiner Meinung nach nicht einmal mehr eine nützliche Richtlinie. Jedes Mal, wenn Sie etwas tun, nur um einen einzigen Rückgabepunkt zu erreichen, überlegen Sie, ob es tatsächlich den Code lesbarer macht.

Ich finde fast immer, dass es das Beste ist, sofort zurückzukehren, wenn ich an einem Punkt im Code den Rückgabewert kenne und keine anderen Aktionen innerhalb der Methode ausführen möchte. Leser dazu zu zwingen, den Rest der Methode durchzulesen nur für den Fall, dass eine weitere Aktion erfolgt, ist weder elegant noch nützlich, meiner Meinung nach.

Ich denke, es ist eine gute Sache, dass eine Methode nicht anzeigen kann, dass sie den Aufrufer zum Rückgabepunkt führen soll - diese Fähigkeit klingt nach einem Lesbarkeitsalbtraum. Nachdem ich das gesagt habe, habe ich über eine neue Art von bedingter Rückkehranweisung nachgedacht:

rückgabe? ausdruck;

Dies würde den ausgewerteten Wert des ausdrucks zurückgeben, wenn er nicht null ist; Sie könnten es für nicht-nullable Typen wie folgt verwenden:

int Foo()
{
    return? Bar(); // Wo Bar() einen Rückgabetyp von int hat?
    ...
}

Im Grunde wäre es das Rückgabestatement-Äquivalent des Null-Kohaleszenzoperators.

Dies würde Ihnen in Ihrem Fall jedoch nicht helfen - Sie möchten frühzeitig null zurückgeben...

0 Stimmen

Ich weiß nicht, als Attribut denke ich, dass es ziemlich lesbar und meiner Meinung nach sauberer als die anderen If-basierten Ansätze wäre. Falls nicht möglich, stimme ich zu, dass die frühe If-Anweisung der richtige Weg ist. Ich denke, eine andere Möglichkeit wäre, einen Codegenerierungs-Schritt zu haben, der die Syntax in eine normale If-Anweisung umschreibt, bevor er kompiliert wird, aber das wäre vielleicht ein wenig übertrieben, auch wenn man auf diese Weise coole Dinge machen könnte, würden neue Programmierer ein wenig verwirrt sein :)

0 Stimmen

@Mattias: Beim Lesen des Aufruf -Codes wäre überhaupt nicht offensichtlich, was passiert. Sie würden das Attribut nicht sehen... wie würden Sie wissen, was zurückgegeben würde? Denken Sie daran, dass einfache Lösungen normalerweise klüger sind.

0 Stimmen

Wenn Sie nur den Aufrufcode lesen, wie würden Sie jemals genau wissen, was die Methode zurückgeben würde, Sie würden nur die Signatur und den Rückgabetyp kennen und das würde das nicht beeinflussen...

4voto

Anders Abel Punkte 65873

Wie wäre es, wenn Sie Ihr erstes Beispiel wie folgt umschreiben:

public SomeClass DoStuff(string inputStr) 
{ 
  if (!IsOpenFilter(inputStr)) 
      return null;

  SomeClass result =null; 

  // Einige Code .... 

  return result; 
} 

Es scheint, als ob Sie versuchen, an der alten Konvention festzuhalten, dass jede Funktion nur einen Rückgabepunkt hat. Kurz gesagt: Ein einzelner Rückgabepunkt stammt aus Sprachen mit explizitem Ressourcenmanagement. Die lange Geschichte ist in einigen alten SO-Beiträgen verfügbar:

0 Stimmen

Ja, es ist eine alte Angewohnheit, die ich vielleicht brechen sollte, es fühlt sich jedoch schwer an, zwei meiner Regeln zu brechen, if-Anweisungen ohne Klammern und immer die return-Anweisung zuletzt zu setzen :) Es wäre sauberer, wenn es eine grundlegende Require-Syntax gäbe, die ich stattdessen verwenden könnte.

1 Stimmen

Du kannst natürlich immer noch Klammern mit der if-Anweisung verwenden. Der andere Punkt, nur einen Rückgabewert zu haben, gehört zu C und anderen "älteren" (oder Low-Level) Sprachen.

0 Stimmen

Ja, aber das ist zu ausführlich :) Ich denke, das Kriterium ist Kürze sowie Einrückung

1voto

Samuell Punkte 81

Diese Lösung kann ziemlich unordentlich sein. ich poste es hier nur zum Spaß als interessante Option.

Sie können den yield return Hack und den Kontrollfluss außerhalb der Funktion verwenden.

So etwas wie das:

public SomeClass Foo(string input)
{
  return FooInner(input)
    .First(i => !i.continueFlow)
    .value;
}

IEnumerable<(bool continueFlow, SomeClass value)> FooInner(string input)
{
  yield return (IsOpenFilter(), null);
  yield return (OtherCondition(), null);

  SomeClass result = null;

  // some code

  yield return (false, result);
}

Dies gibt den ersten Wert zurück, bei dem continueFlow false ist und nicht fortgesetzt wird. Vergessen Sie nicht das letzte yield return - die First-Methode kann eine Ausnahme werfen.

-1voto

DasKrümelmonster Punkte 5681

Also denke ich, es gibt zwei Fragen, kann das irgendwie gemacht werden? Ich bin ratlos, wie man eine bedingte Rückgabe aus dem Aufruf einer Methode machen kann.

Sie haben hier einige Optionen, aber zuerst einmal: Sie benötigen eine Kontrollfluss-Anweisung wie return goto oder throw, um dies zu erreichen.

Das lässt uns also mit diesen Optionen zurück:

  1. Geben Sie frühzeitig null zurück. Dies ist einfach zu erreichen, ausreichend für die meisten Anwendungsfälle und nicht hacky.
  2. Verwenden Sie Contract.Requires(), das eine Exception wirft.
  3. Vielleicht verwenden Sie OneOf<> von NuGet, damit Sie Ausnahmen vermeiden können, aber trotzdem den Grund für den Fehler angeben können.
  4. Trennen Sie die Überprüfungen und die Logik:

Vielleicht so?

public SomeClass? DoStuff(string inputStr)
{
  return ArgumentsValid() ? Logic() : null;

  bool ArgumentsValid() => !IsOpenFilter(inputStr);

  SomeClass Logic()
  { 
    // Logik hier
  }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X