417 Stimmen

Wann ist in vs. ref vs. out zu verwenden?

Neulich fragte mich jemand, wann er das Schlüsselwort "Parameter" verwenden sollte out anstelle von ref . Ich verstehe zwar (glaube ich) den Unterschied zwischen dem ref y out Schlüsselwörter (das war vorher gefragt ) und die beste Erklärung scheint zu sein, dass ref == in y out Was sind einige (hypothetische oder Code-) Beispiele, bei denen ich immer out und nicht ref .

Seit ref allgemeiner ist, warum wollen Sie überhaupt die out ? Ist es nur syntaktischer Zucker?

416voto

peterchen Punkte 39679

Sie sollten Folgendes verwenden out es sei denn, Sie benötigen ref .

Es macht einen großen Unterschied, wenn die Daten z. B. an einen anderen Prozess übergeben werden müssen, was kostspielig sein kann. Sie sollten also vermeiden, den Anfangswert zu übertragen, wenn die Methode ihn nicht benötigt.

Darüber hinaus zeigt es dem Leser der Deklaration oder des Aufrufs auch an, ob der Ausgangswert relevant ist (und möglicherweise erhalten bleibt) oder weggeworfen wird.

Ein kleiner Unterschied ist, dass ein out-Parameter nicht initialisiert werden muss.

Beispiel für out :

string a, b;
person.GetBothNames(out a, out b);

wo GetBothNames eine Methode ist, um zwei Werte atomar abzurufen, wird die Methode das Verhalten nicht ändern, was auch immer a und b sind. Wenn der Aufruf an einen Server in Hawaii geht, ist das Kopieren der Anfangswerte von hier nach Hawaii eine Verschwendung von Bandbreite. Ein ähnliches Snippet mit ref:

string a = String.Empty, b = String.Empty;
person.GetBothNames(ref a, ref b);

könnte die Leser verwirren, da es so aussieht, als seien die Anfangswerte von a und b relevant (obwohl der Name der Methode darauf hinweisen würde, dass sie es nicht sind).

Beispiel für ref :

string name = textbox.Text;
bool didModify = validator.SuggestValidName(ref name);

Hier ist der Ausgangswert für die Methode relevant.

78voto

Reed Copsey Punkte 536986

Verwenden Sie out, um anzuzeigen, dass der Parameter nicht verwendet wird, sondern nur gesetzt ist. Dies hilft dem Aufrufer zu verstehen, dass Sie den Parameter immer initialisieren.

Außerdem sind ref und out nicht nur für Werttypen geeignet. Sie ermöglichen es auch, das Objekt, auf das ein Referenztyp verweist, innerhalb einer Methode zurückzusetzen.

41voto

Adam Robinson Punkte 176996

Das ist semantisch gesehen richtig, ref bietet sowohl "In"- als auch "Out"-Funktionalität, während out bietet nur eine "Out"-Funktionalität. Es gibt einige Dinge zu beachten:

  1. out verlangt, dass die Methode, die den Parameter annimmt, zu irgendeinem Zeitpunkt vor der Rückkehr der Variablen einen Wert zuweisen MUSS. Sie finden dieses Muster in einigen der Schlüssel/Wert-Datenspeicherklassen wie Dictionary<K,V> , wo Sie Funktionen haben wie TryGetValue . Diese Funktion nimmt eine out Parameter, der den Wert enthält, wenn er abgerufen wird. Es wäre nicht sinnvoll, wenn der Aufrufer einen Wert übergeben würde in diese Funktion, also out wird verwendet, um zu garantieren, dass nach dem Aufruf ein Wert in der Variablen vorhanden ist, auch wenn es sich nicht um "echte" Daten handelt (im Fall von TryGetValue wo der Schlüssel nicht vorhanden ist).
  2. out y ref Parameter werden beim Umgang mit Interop-Code unterschiedlich gehandhabt

Außerdem ist es wichtig zu wissen, dass sich Referenztypen und Werttypen zwar in der Art ihres Wertes unterscheiden, jede Variable in Ihrer Anwendung verweist auf einen Speicherplatz, der einen Wert enthält auch für Referenztypen. Bei Referenztypen ist der Wert, der an dieser Stelle im Speicher enthalten ist, zufällig eine andere Speicherplatz. Wenn Sie Werte an eine Funktion übergeben (oder eine andere Variablenzuweisung vornehmen), wird der Wert dieser Variablen in die andere Variable kopiert. Bei Werttypen bedeutet dies, dass der gesamte Inhalt des Typs kopiert wird. Bei Referenztypen bedeutet dies, dass der Speicherplatz kopiert wird. In jedem Fall wird eine Kopie der in der Variablen enthaltenen Daten erstellt. Die einzige wirkliche Bedeutung, die dies hat, betrifft die Semantik der Zuweisung; wenn eine Variable zugewiesen oder als Wert übergeben wird (die Standardeinstellung), wirkt sich eine neue Zuweisung an die ursprüngliche (oder neue) Variable nicht auf die andere Variable aus. Im Falle von Referenztypen, ja, Änderungen, die an der instance sind auf beiden Seiten verfügbar, aber das liegt daran, dass die eigentliche Variable nur ein Zeiger auf eine andere Speicherstelle ist; der Inhalt der Variablen - die Speicherstelle - hat sich nicht wirklich geändert.

Passieren mit dem ref Schlüsselwort besagt, dass sowohl die ursprüngliche Variable y verweist der Funktionsparameter tatsächlich auf denselben Speicherplatz. Dies betrifft wiederum nur die Semantik der Zuweisung. Wenn einer der Variablen ein neuer Wert zugewiesen wird, wird der neue Wert auf der anderen Seite wiedergegeben, da die andere auf denselben Speicherplatz zeigt.

28voto

Lorenz Lo Sauer Punkte 22044

Sie hängt vom Kompilierkontext ab (siehe Beispiel unten).

out y ref bezeichnen beide die Übergabe von Variablen durch Verweis, doch ref erfordert, dass die Variable vor der Übergabe initialisiert wird, was ein wichtiger Unterschied im Zusammenhang mit Marshaling sein kann (Interop: UmanagedToManagedTransition oder umgekehrt)

MSDN warnt :

Verwechseln Sie das Konzept der Übergabe durch Referenz nicht mit dem Konzept der Referenztypen. Die beiden Konzepte sind nicht identisch. Ein Methodenparameter kann durch ref geändert werden, unabhängig davon, ob es sich um einen Werttyp oder einen Referenztyp handelt. Bei der Referenzübergabe wird ein Wertetyp nicht gepackt.

Aus den offiziellen MSDN Docs:

Das Schlüsselwort out bewirkt, dass die Argumente als Referenz übergeben werden. Dies ist ähnlich wie das ref-Schlüsselwort, mit dem Unterschied, dass ref erfordert, dass die Variable initialisiert wird, bevor sie übergeben wird

Das Schlüsselwort ref bewirkt, dass ein Argument als Referenz und nicht als Wert übergeben wird. Die Übergabe per Verweis hat zur Folge, dass jede Änderung des Parameters in der Methode sich in der zugrunde liegenden Argumentvariablen in der aufrufenden Methode niederschlägt. Der Wert eines Referenzparameters ist immer derselbe wie der Wert der zugrunde liegenden Argumentvariablen.

Wir können überprüfen, ob out und ref tatsächlich dasselbe sind, wenn das Argument zugewiesen wird:

CIL Beispiel :

Betrachten Sie das folgende Beispiel

static class outRefTest{
    public static int myfunc(int x){x=0; return x; }
    public static void myfuncOut(out int x){x=0;}
    public static void myfuncRef(ref int x){x=0;}
    public static void myfuncRefEmpty(ref int x){}
    // Define other methods and classes here
}

in CIL, die Anweisungen von myfuncOut y myfuncRef sind erwartungsgemäß identisch.

outRefTest.myfunc:
IL_0000:  nop         
IL_0001:  ldc.i4.0    
IL_0002:  starg.s     00 
IL_0004:  ldarg.0     
IL_0005:  stloc.0     
IL_0006:  br.s        IL_0008
IL_0008:  ldloc.0     
IL_0009:  ret         

outRefTest.myfuncOut:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  stind.i4    
IL_0004:  ret         

outRefTest.myfuncRef:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldc.i4.0    
IL_0003:  stind.i4    
IL_0004:  ret         

outRefTest.myfuncRefEmpty:
IL_0000:  nop         
IL_0001:  ret         

nop : kein Betrieb, ldloc : lokal laden, stloc : Stapel lokal, ldarg : Argument laden, Der Teufel steckt im Detail. Verzweigung zum Ziel....

(Siehe: Liste der CIL-Anweisungen )

25voto

Shivprasad Koirala Punkte 25296

Im Folgenden finden Sie einige Hinweise, die ich diesem Codeproject-Artikel entnommen habe C# Out vs. Ref

  1. Es sollte nur verwendet werden, wenn wir mehrere Ausgaben von einer Funktion oder einer Methode erwarten. Ein Gedanke über Strukturen kann auch eine gute Option für dasselbe sein.
  2. REF und OUT sind Schlüsselwörter, die festlegen, wie Daten vom Aufrufer an den Empfänger und umgekehrt übergeben werden.
  3. Im REF werden die Daten in zwei Richtungen weitergeleitet. Vom Aufrufer zum Angerufenen und umgekehrt.
  4. In-Out-Daten werden nur in einer Richtung vom Anrufer zum Anrufer weitergeleitet. Wenn in diesem Fall der Anrufer versucht, Daten an den Anrufer zu senden, werden diese übersehen/abgelehnt.

Wenn Sie ein visueller Mensch sind, sehen Sie sich bitte dieses YouTube-Video an, das den Unterschied praktisch veranschaulicht https://www.youtube.com/watch?v=lYdcY5zulXA

Das folgende Bild zeigt die Unterschiede visuell besser

C# Out Vs Ref

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