Wenn wir einen Wert von einer Methode erhalten möchten, können wir einen der folgenden Rückgabewerte verwenden:
public int GetValue();
oder:
public void GetValue(out int x);
Ich verstehe die Unterschiede zwischen ihnen nicht wirklich und weiß daher nicht, was besser ist. Kannst du mir das erklären?
Danke dir.
Tuple
wenn Sie möchten, aber der allgemeine Konsens ist, dass, wenn Sie mehr als eine Sache zurückgeben müssen, die Dinge normalerweise irgendwie zusammenhängen und diese Beziehung normalerweise am besten als Klasse ausgedrückt wird.return Tuple.Create(x, y, z);
Ist das nicht hässlich ? Außerdem ist es spät am Tag, sie auf Sprachniveau einzuführen. Der Grund, warum ich keine Klasse erstellen würde, um Werte aus einem ref / out-Parameter zurückzugeben, ist, dass ref / out-Parameter nur für große veränderbare Strukturen (wie Matrizen) oder optionale Werte wirklich Sinn machen und letzteres umstritten ist.Tuple<>
und C # -Tupel!. Ich wünschte nur, C # würde die Rückgabe anonymer Typen von Methoden mit vom Compiler abgeleitetem Typauto
erlauben (wie in Dlang).Antworten:
Rückgabewerte sind fast immer die richtige Wahl, wenn die Methode nichts anderes zurückzugeben hat. (Tatsächlich kann ich mir keine Fälle vorstellen , in denen ich jemals eine void-Methode mit einem
out
Parameter haben möchte , wenn ich die Wahl hätte. DieDeconstruct
Methoden von C # 7 für die sprachgestützte Dekonstruktion sind eine sehr, sehr seltene Ausnahme von dieser Regel .)Abgesehen von allem anderen verhindert dies, dass der Aufrufer die Variable separat deklarieren muss:
vs.
Out-Werte verhindern auch die Verkettung von Methoden wie folgt:
(In der Tat ist dies auch eines der Probleme bei Eigenschaftssetzern, und deshalb verwendet das Builder-Muster Methoden, die den Builder zurückgeben, z
myStringBuilder.Append(xxx).Append(yyy)
.Darüber hinaus sind Out-Parameter bei der Reflexion etwas schwieriger zu verwenden und erschweren normalerweise auch das Testen. (Normalerweise wird mehr Aufwand betrieben, um das Verspotten von Rückgabewerten zu vereinfachen als das Herausgeben von Parametern). Grundsätzlich fällt mir nichts ein, was sie einfacher machen ...
Rückgabewerte FTW.
EDIT: In Bezug auf was los ist ...
Grundsätzlich , wenn Sie in einem Argument für ein „out“ Parameter übergeben, Sie haben in einer Variable übergeben. (Array-Elemente werden auch als Variablen klassifiziert.) Die von Ihnen aufgerufene Methode hat keine "neue" Variable auf ihrem Stapel für den Parameter - sie verwendet Ihre Variable zum Speichern. Änderungen an der Variablen sind sofort sichtbar. Hier ist ein Beispiel, das den Unterschied zeigt:
Ergebnisse:
Der Unterschied liegt im Schritt "post" - dh nachdem die lokale Variable oder der lokale Parameter geändert wurde. Im ReturnValue-Test macht dies keinen Unterschied zur statischen
value
Variablen. Im OutParameter-Test wird dievalue
Variable durch die Zeile geänderttmp = 10;
quelle
Dictionary.TryGetValue
hier nicht anwendbar ist, da dies keine nichtige Methode ist. Können Sie erklären, warum Sie einenout
Parameter anstelle eines Rückgabewerts wünschen ? (Auch fürTryGetValue
, ich würde einen Rückgabewert bevorzugen, der alle Ausgabeinformationen persönlich enthält. Siehe NodaTimeParseResult<T>
für ein Beispiel, wie ich es entworfen hätte.)out
Parameter nichts mit dem Wert anfangen können.Was besser ist, hängt von Ihrer speziellen Situation ab. Einer der Gründe
out
besteht darin, die Rückgabe mehrerer Werte aus einem Methodenaufruf zu erleichtern:Das eine ist also per Definition nicht besser als das andere. Normalerweise möchten Sie jedoch eine einfache Rückgabe verwenden, es sei denn, Sie haben beispielsweise die oben genannte Situation.
BEARBEITEN: Dies ist ein Beispiel, das einen der Gründe für das Vorhandensein des Schlüsselworts zeigt. Das oben Gesagte kann in keiner Weise als Best Practice angesehen werden.
quelle
Sie sollten im Allgemeinen einen Rückgabewert einem out-Parameter vorziehen. Unsere Parameter sind ein notwendiges Übel, wenn Sie Code schreiben, der zwei Dinge tun muss. Ein gutes Beispiel hierfür ist das Try-Muster (z. B. Int32.TryParse).
Lassen Sie uns überlegen, was der Aufrufer Ihrer beiden Methoden tun müsste. Für das erste Beispiel kann ich das schreiben ...
Beachten Sie, dass ich eine Variable deklarieren und über Ihre Methode in einer Zeile zuweisen kann. Für das 2. Beispiel sieht es so aus ...
Ich bin jetzt gezwungen, meine Variable im Voraus zu deklarieren und meinen Code über zwei Zeilen zu schreiben.
aktualisieren
Ein guter Ort, um diese Art von Fragen zu stellen, sind die .NET Framework-Entwurfsrichtlinien. Wenn Sie die Buchversion haben, können Sie die Anmerkungen von Anders Hejlsberg und anderen zu diesem Thema sehen (Seite 184-185), aber die Online-Version ist hier ...
http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx
Wenn Sie zwei Dinge von einer API zurückgeben müssen, ist es besser, sie in eine Struktur / Klasse einzupacken, als einen out-Parameter.
quelle
Es gibt einen Grund, einen
out
Parameter zu verwenden, der noch nicht erwähnt wurde: Die aufrufende Methode ist verpflichtet, ihn zu empfangen. Wenn Ihre Methode einen Wert erzeugt, den der Aufrufer nicht verwerfen sollte, wird der Aufrufer gezwungen, ihnout
ausdrücklich zu akzeptieren:Natürlich kann der Aufrufer den Wert in einem
out
Parameter immer noch ignorieren , aber Sie haben seine Aufmerksamkeit darauf gelenkt.Dies ist ein seltener Bedarf; häufiger sollten Sie eine Ausnahme für ein echtes Problem verwenden oder ein Objekt mit Statusinformationen für eine "FYI" zurückgeben, aber es kann Umstände geben, unter denen dies wichtig ist.
quelle
Es ist hauptsächlich die Präferenz
Ich bevorzuge Retouren und wenn Sie mehrere Retouren haben, können Sie diese in ein Ergebnis-DTO einschließen
quelle
Sie können nur einen Rückgabewert haben, während Sie mehrere Out-Parameter haben können.
Sie müssen nur in diesen Fällen Parameter berücksichtigen.
Wenn Sie jedoch mehr als einen Parameter von Ihrer Methode zurückgeben müssen, möchten Sie sich wahrscheinlich ansehen, was Sie von einem OO-Ansatz zurückgeben, und überlegen, ob Sie ein Objekt oder eine Struktur mit diesen Parametern besser zurückgeben sollten. Daher kehren Sie wieder zu einem Rückgabewert zurück.
quelle
Sie sollten fast immer einen Rückgabewert verwenden. '
out
' Parameter verursachen ein wenig Reibung bei vielen APIs, der Komposition usw.Die bemerkenswerteste Ausnahme, die Ihnen in den Sinn kommt, ist, wenn Sie mehrere Werte zurückgeben möchten (.Net Framework hat bis 4.0 keine Tupel), z. B. mit dem
TryParse
Muster.quelle
Ich würde das Folgende anstelle eines der beiden in diesem einfachen Beispiel bevorzugen.
Aber sie sind alle sehr ähnlich. Normalerweise würde man 'out' nur verwenden, wenn mehrere Werte von der Methode zurückgegeben werden müssen. Wenn Sie einen Wert in und aus der Methode senden möchten, wählen Sie 'ref'. Meine Methode ist am besten, wenn Sie nur einen Wert zurückgeben, aber wenn Sie einen Parameter übergeben und einen Wert zurückerhalten möchten, wählen Sie wahrscheinlich Ihre erste Wahl.
quelle
Ich denke, eines der wenigen Szenarien, in denen es nützlich wäre, wäre die Arbeit mit nicht verwaltetem Speicher, und Sie möchten klarstellen, dass der "zurückgegebene" Wert manuell entsorgt werden sollte, anstatt zu erwarten, dass er selbst entsorgt wird .
quelle
Darüber hinaus sind Rückgabewerte mit asynchronen Entwurfsparadigmen kompatibel.
Sie können eine Funktion nicht als "asynchron" festlegen, wenn sie ref- oder out-Parameter verwendet.
Zusammenfassend lässt sich sagen, dass Rückgabewerte eine Verkettung von Methoden und eine sauberere Syntax ermöglichen (da der Aufrufer keine zusätzlichen Variablen mehr deklarieren muss) und asynchrone Designs ermöglichen, ohne dass in Zukunft wesentliche Änderungen erforderlich sind.
quelle
Beide haben einen unterschiedlichen Zweck und werden vom Compiler nicht gleich behandelt. Wenn Ihre Methode einen Wert zurückgeben muss, müssen Sie return verwenden. Out wird verwendet, wenn Ihre Methode mehrere Werte zurückgeben muss.
Wenn Sie return verwenden, werden die Daten zuerst in den Methodenstapel und dann in die aufrufenden Methoden geschrieben. Im Falle von out wird es direkt in den aufrufenden Methodenstapel geschrieben. Ich bin mir nicht sicher, ob es weitere Unterschiede gibt.
quelle
Wie andere gesagt haben: Rückgabewert, nicht out param.
Darf ich Ihnen das Buch "Framework Design Guidelines" (2. Aufl.) Empfehlen? Die Seiten 184-185 behandeln die Gründe für das Vermeiden von Parametern. Das ganze Buch wird Sie bei allen Arten von .NET-Codierungsproblemen in die richtige Richtung lenken.
Verbunden mit den Framework Design Guidelines ist die Verwendung des statischen Analysetools FxCop. Sie finden dies auf den Microsoft-Websites als kostenlosen Download. Führen Sie dies auf Ihrem kompilierten Code aus und sehen Sie, was darin steht. Wenn es sich über Hunderte und Hunderte von Dingen beschwert ... keine Panik! Schauen Sie sich ruhig und genau an, was in jedem Fall steht. Beeilen Sie sich nicht, um Dinge so schnell wie möglich zu reparieren. Lerne aus dem, was es dir sagt. Sie werden auf den Weg zur Meisterschaft gebracht.
quelle
Die Verwendung des Schlüsselworts out mit einem Rückgabetyp von bool kann manchmal das Aufblähen des Codes verringern und die Lesbarkeit verbessern. (In erster Linie, wenn die zusätzlichen Informationen im Parameter out häufig ignoriert werden.) Zum Beispiel:
vs:
quelle
Es gibt keinen wirklichen Unterschied. Unsere Parameter sind in C # angegeben, damit die Methode mehr als einen Wert zurückgeben kann. Das ist alles.
Es gibt jedoch einige geringfügige Unterschiede, von denen jedoch keine wirklich wichtig sind:
Wenn Sie den Parameter out verwenden, müssen Sie zwei Zeilen verwenden:
Wenn Sie den Rückgabewert verwenden, können Sie dies in einer Zeile tun:
Ein weiterer Unterschied (nur für Werttypen korrekt und nur dann, wenn C # die Funktion nicht integriert) besteht darin, dass bei Verwendung der Rückgabewert bei der Rückgabe der Funktion unbedingt eine Kopie des Werts erstellt wird, bei Verwendung des Parameters OUT nicht unbedingt.
quelle
out ist nützlicher, wenn Sie versuchen, ein Objekt zurückzugeben, das Sie in der Methode deklariert haben.
Beispiel
quelle
Rückgabewert ist der normale Wert, der von Ihrer Methode zurückgegeben wird.
Wo als out- Parameter, well out und ref zwei Schlüsselwörter von C # sind, können Variablen als Referenz übergeben werden .
Der große Unterschied zwischen ref und out ist, ref sollte vor und initialisiert wurde aus nicht
quelle
Ich vermute, ich werde mich nicht mit dieser Frage befassen, aber ich bin ein sehr erfahrener Programmierer, und ich hoffe, dass einige der aufgeschlosseneren Leser darauf achten werden.
Ich glaube, dass es für objektorientierte Programmiersprachen besser geeignet ist, wenn ihre Value-Returning-Verfahren (VRPs) deterministisch und rein sind.
'VRP' ist der moderne akademische Name für eine Funktion, die als Teil eines Ausdrucks aufgerufen wird und einen Rückgabewert hat, der den Aufruf während der Auswertung des Ausdrucks fiktiv ersetzt. ZB in einer Anweisung wie
x = 1 + f(y)
der Funktionf
dient die Funktion als VRP.'Deterministisch' bedeutet, dass das Ergebnis der Funktion nur von den Werten ihrer Parameter abhängt. Wenn Sie es erneut mit denselben Parameterwerten aufrufen, erhalten Sie mit Sicherheit dasselbe Ergebnis.
'Rein' bedeutet keine Nebenwirkungen: Der Aufruf der Funktion bewirkt nichts anderes als die Berechnung des Ergebnisses. Dies kann so interpretiert werden, dass es in der Praxis keine wichtigen Nebenwirkungen gibt. Wenn der VRP beispielsweise bei jedem Aufruf eine Debugging-Nachricht ausgibt, kann dies wahrscheinlich ignoriert werden.
Wenn Ihre Funktion in C # nicht deterministisch und rein ist, sollten Sie sie zu einer
void
Funktion machen (mit anderen Worten, nicht zu einem VRP), und jeder Wert, den sie zurückgeben muss, sollte entweder in einemout
oder einemref
Parameter zurückgegeben werden.Wenn Sie beispielsweise eine Funktion zum Löschen einiger Zeilen aus einer Datenbanktabelle haben und möchten, dass diese die Anzahl der gelöschten Zeilen zurückgibt, sollten Sie Folgendes deklarieren:
public void DeleteBasketItems(BasketItemCategory category, out int count);
Wenn Sie diese Funktion manchmal aufrufen möchten, aber die nicht erhalten möchten
count
, können Sie jederzeit eine Überladung deklarieren.Vielleicht möchten Sie wissen, warum dieser Stil besser zur objektorientierten Programmierung passt. Im Großen und Ganzen passt es in einen Programmierstil, der (etwas ungenau) als "prozedurale Programmierung" bezeichnet werden könnte, und es ist ein prozeduraler Programmierstil, der besser zur objektorientierten Programmierung passt.
Warum? Das klassische Modell von Objekten besteht darin, dass sie Eigenschaften (auch Attribute genannt) haben und Sie das Objekt (hauptsächlich) abfragen und bearbeiten, indem Sie diese Eigenschaften lesen und aktualisieren. Ein prozeduraler Programmierstil erleichtert dies in der Regel, da Sie zwischen Operationen, die Eigenschaften abrufen und festlegen, beliebigen Code ausführen können.
Der Nachteil der prozeduralen Programmierung besteht darin, dass Sie, da Sie überall beliebigen Code ausführen können, über globale Variablen und Nebenwirkungen einige sehr stumpfe und fehleranfällige Interaktionen erhalten können.
Es ist also ganz einfach eine gute Praxis, jemandem, der Ihren Code liest, zu signalisieren , dass eine Funktion Nebenwirkungen haben kann, indem sie nicht wertmäßig zurückgegeben wird.
quelle
_
Discard-Symbol verwenden, um einen out-Parameter zu ignorieren, z. B.: DeleteBasketItems (category, out _);