Wann in vs ref vs out zu verwenden


383

Jemand hat mich neulich gefragt, wann sie das Parameter-Schlüsselwort outanstelle von verwenden sollen ref. Während ich (glaube ich) den Unterschied zwischen den Schlüsselwörtern refund out(die zuvor gefragt wurden ) verstehe und die beste Erklärung zu sein scheint, ist ref== inund out, was sind einige (hypothetische oder Code-) Beispiele, bei denen ich immer verwenden sollte outund nicht ref.

Da refist allgemeiner, warum möchten Sie jemals verwenden out? Ist es nur syntaktischer Zucker?


18
Eine mit übergeben übergebene Variable outkann nicht gelesen werden, bevor sie zugewiesen wurde. refhat diese Einschränkung nicht. Da ist also das.
Corey Ogburn

17
Kurz gesagt, refist für In / Out, während outes sich um einen Nur-Out-Parameter handelt.
Tim S.

3
Was genau verstehst du nicht?
tnw

4
Auch outVariablen MÜSSEN in der Funktion zugewiesen werden.
Corey Ogburn

Danke Corey. Aber das habe ich schon nicht. Mein Punkt ist, was der Vorteil davon ist. Eigentlich brauche ich ein Beispiel, das ein Szenario zeigt, in dem wir den Parameter ref verwenden können, um eine Funktionalität zu erreichen, die mit dem Parameter out nicht erreicht werden kann, und umgekehrt.
Rajbir Singh

Antworten:


399

Sie sollten verwenden, es outsei denn, Sie benötigen ref.

Es macht einen großen Unterschied, wenn die Daten z. B. in einen anderen Prozess übertragen werden müssen, was kostspielig sein kann. Sie möchten also vermeiden, den Anfangswert zu marshallen, wenn die Methode ihn nicht verwendet.

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

Als kleiner Unterschied muss ein out-Parameter nicht initialisiert werden.

Beispiel für out:

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

Wenn GetBothNames eine Methode zum atomaren Abrufen von zwei Werten ist, ändert die Methode das Verhalten unabhängig von a und b nicht. Wenn der Anruf 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 wären die Anfangswerte von a und b relevant (obwohl der Methodenname anzeigen würde, dass dies nicht der Fall ist).

Beispiel für ref:

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

Hier ist der Anfangswert methodisch relevant.


5
"Das ist nicht wirklich der Fall." - Können Sie bitte besser erklären, was Sie meinen?
Peterchen

3
Sie möchten nicht reffür Standardwerte verwenden.
C.Evenhuis

155
Für die Nachwelt: Ein weiterer Unterschied, den niemand sonst erwähnt zu haben scheint, wie hier angegeben ; für einen outParameter, wird der Aufruf der Methode erforderlichen Wert , bevor das Verfahren kehrt zuordnen. - Sie müssen nicht haben , um mit einem ref Parameter nichts zu tun.
Brichins

3
@brichins Bitte lesen Sie den Abschnitt "Kommentare (Community-Ergänzungen)" in dem von Ihnen erwähnten Link . Dies ist ein Fehler, der in der VS 2008-Dokumentation behoben wurde.
Bharat Ram V

13
@brichins Die aufgerufene Methode ist erforderlich, um einen Wert zuzuweisen, nicht die aufrufende Methode. zverev.eugene Dies wurde in der VS 2008-Dokumentation korrigiert.
Segfault

72

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

Ref und out gelten nicht nur für Werttypen. Sie können auch das Objekt, auf das ein Referenztyp verweist, innerhalb einer Methode zurücksetzen.


3
+1 Ich wusste nicht, dass es auch für Referenztypen verwendet werden kann, schöne klare Antwort, danke
Dale

@brichins: Nein, kannst du nicht. outParameter werden beim Eintritt in die Funktion als nicht zugewiesen behandelt. Sie können ihren Wert erst überprüfen, wenn Sie zuerst einen bestimmten Wert zugewiesen haben. Es gibt überhaupt keine Möglichkeit, den Wert zu verwenden, den der Parameter beim Aufruf der Funktion hatte.
Ben Voigt

Richtig, Sie können vor einer internen Zuweisung nicht auf den Wert zugreifen. Ich bezog sich auf die Tatsache , dass der Parameter selbst kann später in dem Verfahren verwendet werden - es ist nicht gesperrt ist. Ob dies tatsächlich getan werden sollte oder nicht, ist eine andere Diskussion (über das Design); Ich wollte nur darauf hinweisen, dass es möglich ist. Danke für die Klarstellung.
Brichins

2
@ ดาว: Kann mit Referenztypen verwendet werden, da bei der Übergabe eines Referenztypparameters der Wert der Referenz und nicht das Objekt selbst übergeben wird. Es ist also immer noch Wertübergabe.
Tarik

38

Sie haben insofern Recht, als Sie semantisch refsowohl "In" - als auch "Out" -Funktionalität outbereitstellen , während Sie nur "Out" -Funktionalität bereitstellen. Es gibt einige Dinge zu beachten:

  1. outerfordert, dass die Methode, die den Parameter akzeptiert, der Variablen irgendwann vor der Rückgabe einen Wert zuweisen muss. Sie finden dieses Muster in einigen der Schlüssel- / Wertdatenspeicherklassen wie Dictionary<K,V>, wo Sie Funktionen wie haben TryGetValue. Diese Funktion verwendet einen outParameter, der den Wert enthält, der beim Abrufen angezeigt wird. Es wäre für den Aufrufer nicht sinnvoll, einen Wert an diese Funktion zu übergeben. Daher outwird verwendet, um sicherzustellen, dass sich nach dem Aufruf ein Wert in der Variablen befindet, auch wenn es sich nicht um "echte" Daten handelt (im Fall von TryGetValuewhere) der Schlüssel ist nicht vorhanden).
  2. outund refParameter werden beim Umgang mit Interop-Code unterschiedlich gemarshallt

Abgesehen davon ist es wichtig zu beachten, dass Referenztypen und Werttypen sich zwar in der Art ihres Werts unterscheiden, jede Variable in Ihrer Anwendung jedoch auf einen Speicherort verweist, der einen Wert enthält , selbst für Referenztypen. Es kommt nur vor, dass bei Referenztypen der in diesem Speicherort enthaltene Wert ein anderer istSpeicherort. Wenn Sie Werte an eine Funktion übergeben (oder eine andere Variablenzuweisung vornehmen), wird der Wert dieser Variablen in die andere Variable kopiert. Für Werttypen bedeutet dies, dass der gesamte Inhalt des Typs kopiert wird. Für Referenztypen bedeutet dies, dass der Speicherort kopiert wird. In beiden Fällen wird eine Kopie der in der Variablen enthaltenen Daten erstellt. Die einzige wirkliche Relevanz, die dies hat, betrifft die Zuweisungssemantik; Wenn eine Variable zugewiesen oder ein Wert übergeben wird (Standardeinstellung), wenn eine neue Zuweisung zur ursprünglichen (oder neuen) Variablen vorgenommen wird, wirkt sich dies nicht auf die andere Variable aus. Bei Referenztypen ja, Änderungen an der Instanzsind auf beiden Seiten verfügbar, aber das liegt daran, dass die tatsächliche Variable nur ein Zeiger auf einen anderen Speicherort ist. Der Inhalt der Variablen - der Speicherort - hat sich nicht wirklich geändert.

Wenn Sie das refSchlüsselwort übergeben, verweisen sowohl die ursprüngliche Variable als auch der Funktionsparameter tatsächlich auf denselben Speicherort. Dies betrifft wiederum nur die Zuweisungssemantik. Wenn einer der Variablen ein neuer Wert zugewiesen wird, wird der neue Wert auf der anderen Seite angezeigt, da der andere auf denselben Speicherort zeigt.


1
Beachten Sie, dass die Anforderung, dass die aufgerufene Methode einem out-Parameter einen Wert zuweist, vom c # -Compiler und nicht von der zugrunde liegenden IL erzwungen wird. Eine in VB.NET geschriebene Bibliothek entspricht möglicherweise nicht dieser Konvention.
jmoreno

Klingt so, als ob der Verweis tatsächlich dem Dereferenzierungssymbol in C ++ (*) entspricht. Die Passby-Referenz in C # muss dem entsprechen, was C / C ++ als Doppelzeiger (Zeiger auf einen Zeiger) bezeichnet. Daher muss ref den 1. Zeiger dereferenzieren, damit die aufgerufene Methode auf den Speicherort des tatsächlichen Objekts im Kontext zugreifen kann.
Kommen Sie

Ich würde tatsächlich vorschlagen, dass eine korrekte TryGetValueVerwendung refund nicht outexplizit für den Fall, dass der Schlüssel nicht gefunden wird.
NetMage

27

Dies hängt vom Kompilierungskontext ab (siehe Beispiel unten).

outund refbeide bezeichnen das Übergeben von Variablen als Referenz, referfordern jedoch , dass die Variable vor dem Übergeben initialisiert wird, was ein wichtiger Unterschied im Kontext von Marshaling sein kann (Interop: UmanagedToManagedTransition oder umgekehrt)

MSDN warnt :

Verwechseln Sie das Konzept der Referenzübergabe nicht mit dem Konzept der Referenztypen. Die beiden Konzepte sind nicht gleich. Ein Methodenparameter kann durch ref geändert werden, unabhängig davon, ob es sich um einen Werttyp oder einen Referenztyp handelt. Es gibt kein Boxing eines Werttyps, wenn es als Referenz übergeben wird.

Aus den offiziellen MSDN-Dokumenten:

Das Schlüsselwort out bewirkt, dass Argumente als Referenz übergeben werden. Dies ähnelt dem Schlüsselwort ref, außer dass ref erfordert, dass die Variable vor der Übergabe initialisiert wird

Das Schlüsselwort ref bewirkt, dass ein Argument als Referenz und nicht als Wert übergeben wird. Die Übergabe als Referenz bewirkt, dass jede Änderung des Parameters in der Methode in der zugrunde liegenden Argumentvariablen in der aufrufenden Methode widergespiegelt wird. Der Wert eines Referenzparameters entspricht immer dem Wert der zugrunde liegenden Argumentvariablen.

Wir können überprüfen, ob out und ref tatsächlich gleich 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 sind die Anweisungen von myfuncOutund myfuncRefwie erwartet 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 : keine Operation, ldloc : local laden, stloc : stack local, ldarg : Argument laden, bs.s : zum Ziel verzweigen ....

(Siehe: Liste der CIL-Anweisungen )


23

Unten sind einige Notizen, die ich aus diesem Codeprojekt-Artikel auf C # Out Vs Ref gezogen habe

  1. Es sollte nur verwendet werden, wenn wir mehrere Ausgaben von einer Funktion oder einer Methode erwarten. Ein Gedanke an Strukturen kann auch eine gute Option dafür sein.
  2. REF und OUT sind Schlüsselwörter, die bestimmen, wie Daten vom Anrufer an den Angerufenen und umgekehrt weitergegeben werden.
  3. In REF werden Daten in zwei Richtungen übertragen. Vom Anrufer zum Angerufenen und umgekehrt.
  4. In-Out-Daten werden nur auf einem Weg vom Angerufenen zum Anrufer übertragen. In diesem Fall wird der Anrufer, der versucht hat, Daten an den Angerufenen zu senden, übersehen / abgelehnt.

Wenn Sie eine visuelle Person sind, sehen Sie sich bitte Ihr yourtube-Video an, das den Unterschied praktisch unter https://www.youtube.com/watch?v=lYdcY5zulXA zeigt

Das folgende Bild zeigt die Unterschiede visueller

C # Out Vs Ref


1
one-way, two-wayBegriffe könnten hier missbraucht werden. Sie sind eigentlich beide
wechselseitig

17

Sie müssen verwenden, refwenn Sie den Parameter lesen und schreiben möchten. Sie müssen verwenden, outwenn Sie nur schreiben möchten. In der Tat outist dies der Fall, wenn Sie mehr als einen Rückgabewert benötigen oder wenn Sie den normalen Rückgabemechanismus nicht für die Ausgabe verwenden möchten (dies sollte jedoch selten sein).

Es gibt Sprachmechaniken, die diese Anwendungsfälle unterstützen. RefParameter müssen initialisiert worden sein, bevor sie an eine Methode übergeben werden (wobei der Schwerpunkt auf der Tatsache liegt, dass sie schreibgeschützt sind), und outParameter können nicht gelesen werden, bevor ihnen ein Wert zugewiesen wurde, und es wird garantiert, dass sie am Ende von geschrieben wurden die Methode (wobei der Schwerpunkt auf der Tatsache liegt, dass sie nur geschrieben werden). Ein Verstoß gegen diese Grundsätze führt zu einem Fehler bei der Kompilierung.

int x;
Foo(ref x); // error: x is uninitialized

void Bar(out int x) {}  // error: x was not written to

Gibt beispielsweise a int.TryParsezurück boolund akzeptiert einen out intParameter:

int value;
if (int.TryParse(numericString, out value))
{
    /* numericString was parsed into value, now do stuff */
}
else
{
    /* numericString couldn't be parsed */
}

Dies ist ein klares Beispiel für eine Situation, in der Sie zwei Werte ausgeben müssen: das numerische Ergebnis und ob die Konvertierung erfolgreich war oder nicht. Die Autoren der CLR haben sich outhier entschieden, da sie sich nicht darum kümmern, was das intvorher gewesen sein könnte.

Denn refSie können sich Folgendes ansehen Interlocked.Increment:

int x = 4;
Interlocked.Increment(ref x);

Interlocked.Incrementerhöht atomar den Wert von x. Da Sie lesen müssen, um es xzu erhöhen, ist dies eine Situation, in der dies refangemessener ist. Sie kümmern sich total darum, was xwar, bevor es weitergegeben wurde Increment.

In der nächsten Version von C # wird es sogar möglich sein, Variablen in outParametern zu deklarieren , wodurch die reine Ausgabe noch stärker betont wird:

if (int.TryParse(numericString, out int value))
{
    // 'value' exists and was declared in the `if` statement
}
else
{
    // conversion didn't work, 'value' doesn't exist here
}

Danke zneak für deine Antwort. Aber können Sie mir erklären, warum ich einen Parameter nicht zum Lesen und Schreiben verwenden konnte?
Rajbir Singh

@RajbirSingh, da outParameter nicht unbedingt initialisiert wurden, sodass der Compiler Sie erst dann von einem outParameter lesen lässt , wenn Sie etwas darauf geschrieben haben.
Zneak

zneak, ich stimmte dir zu. Im folgenden Beispiel kann ein out-Parameter jedoch als Lese- und Schreibzugriff verwendet werden: string name = "myName"; private void OutMethod (out string nameOut) {if (nameOut == "myName") {nameOut = "Rajbir Singh in out method"; }}
Rajbir Singh

1
@RajbirSingh, dein Beispiel wird nicht kompiliert. Sie können nameOutIhre ifErklärung nicht einlesen , da ihr zuvor nichts zugewiesen wurde.
Zneak

Danke @zneak. Du liegst absolut richtig. Es wird nicht kompiliert. Vielen Dank für meine Hilfe und jetzt macht es Sinn für mich :)
Rajbir Singh

7

outist mehr Constraint-Version von ref.

In einem Methodenkörper müssen Sie allen outParametern zuweisen, bevor Sie die Methode verlassen. Auch Werte, die einem outParameter zugewiesen sind, werden ignoriert, während refsie zugewiesen werden müssen.

So outkönnen Sie Folgendes tun:

int a, b, c = foo(out a, out b);

wo refmüsste a und b zugewiesen werden.


Wenn überhaupt, outist die weniger eingeschränkte Version. refhat "Voraussetzung: Variable ist definitiv zugewiesen, Nachbedingung: Variable ist definitiv zugewiesen", während outnur "Nachbedingung: Variable ist definitiv zugewiesen" (und wie erwartet ist mehr für eine Funktionsimplementierung mit weniger Voraussetzungen erforderlich)
Ben Voigt

@ BenVoigt: Vermutlich hängt das davon ab, in welche Richtung Sie schauen :) Ich denke, ich meinte Einschränkung in Bezug auf die Codierungsflexibilität (?).
Leppie

7

Wie es sich anhört:

out = nur initialize / füllen einen Parameter (Parameter muss leer sein) zurückgeben out Ebene

ref = Referenz, Standardparameter (mit Wert), aber die Funktion ist es zu modifizieren.


Die Parametervariable out kann einen Wert erhalten, bevor Sie ihn an eine Methode übergeben.
Bence Végert

6

Sie können das outKontextschlüsselwort in zwei Kontexten (jeder ist ein Link zu detaillierten Informationen), als Parametermodifikator oder in generischen Typparameterdeklarationen in Schnittstellen und Delegaten verwenden. In diesem Thema wird der Parametermodifikator erläutert. In diesem anderen Thema finden Sie Informationen zu den generischen Typparameterdeklarationen.

Das outSchlüsselwort bewirkt, dass Argumente als Referenz übergeben werden. Dies ist wie das refSchlüsselwort, außer dass refdie Variable vor der Übergabe initialisiert werden muss. Um einen outParameter zu verwenden, müssen sowohl die Methodendefinition als auch die aufrufende Methode das outSchlüsselwort explizit verwenden . Zum Beispiel: C #

class OutExample
{
    static void Method(out int i)
    {
        i = 44;
    }
    static void Main()
    {
        int value;
        Method(out value);
        // value is now 44
    }
}

Obwohl als outArgumente übergebene Variablen vor der Übergabe nicht initialisiert werden müssen, muss die aufgerufene Methode einen Wert zuweisen, bevor die Methode zurückgegeben wird.

Obwohl die Schlüsselwörter refund outein unterschiedliches Laufzeitverhalten verursachen, werden sie zur Kompilierungszeit nicht als Teil der Methodensignatur betrachtet. Daher können Methoden nicht überladen werden, wenn der einzige Unterschied darin besteht, dass eine Methode ein refArgument und die andere ein outArgument verwendet. Der folgende Code wird beispielsweise nicht kompiliert: C #

class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded 
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

Das Überladen kann jedoch erfolgen, wenn eine Methode ein refoder- outArgument verwendet und die andere keines verwendet, wie folgt: C #

class OutOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(out int i) { i = 5; }
}

Eigenschaften sind keine Variablen und können daher nicht als outParameter übergeben werden.

Informationen zum Übergeben von Arrays finden Sie unter Übergeben von Arrays mit refund out(C # -Programmierhandbuch).

Sie können die Schlüsselwörter refund nicht outfür die folgenden Arten von Methoden verwenden:

Async methods, which you define by using the async modifier.

Iterator methods, which include a yield return or yield break statement.

Beispiel

Das Deklarieren einer outMethode ist nützlich, wenn eine Methode mehrere Werte zurückgeben soll. Im folgenden Beispiel werden outdrei Variablen mit einem einzigen Methodenaufruf zurückgegeben. Beachten Sie, dass das dritte Argument null zugewiesen ist. Dadurch können Methoden optional Werte zurückgeben. C #

class OutReturnExample
{
    static void Method(out int i, out string s1, out string s2)
    {
        i = 44;
        s1 = "I've been returned";
        s2 = null;
    }
    static void Main()
    {
        int value;
        string str1, str2;
        Method(out value, out str1, out str2);
        // value is now 44
        // str1 is now "I've been returned"
        // str2 is (still) null;
    }
}

6

Wie benutzt man inoder outoder refin C #?

  • Alle Schlüsselwörter in C#haben die gleiche Funktionalität, jedoch einige Grenzen .
  • in Argumente können mit der aufgerufenen Methode nicht geändert werden.
  • ref Argumente können geändert werden.
  • ref muss initialisiert werden, bevor es vom Aufrufer verwendet wird. Es kann in der Methode gelesen und aktualisiert werden.
  • out Argumente müssen vom Aufrufer geändert werden.
  • out Argumente müssen in der Methode initialisiert werden
  • Als inArgumente übergebene Variablen müssen initialisiert werden, bevor sie in einem Methodenaufruf übergeben werden. Die aufgerufene Methode darf jedoch keinen Wert zuweisen oder das Argument ändern.

Sie können nicht verwenden Sie die in, refund outSchlüsselwörter für die folgenden Arten von Methoden:

  • Asynchrone Methoden , die Sie mithilfe des asyncModifikators definieren.
  • Iterator-Methoden , die eine yield returnoder- yield breakAnweisung enthalten.

5

Nur um den Kommentar von OP zu verdeutlichen, dass die Verwendung von ref und out ein "Verweis auf einen Werttyp oder eine Struktur ist, die außerhalb der Methode deklariert wurde", der bereits als falsch festgelegt wurde.

Betrachten Sie die Verwendung von ref in einem StringBuilder, einem Referenztyp:

private void Nullify(StringBuilder sb, string message)
{
    sb.Append(message);
    sb = null;
}

// -- snip --

StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(sb, message);
System.Console.WriteLine(sb.ToString());

// Output
// Hi Guy

Wie dazu bestimmt:

private void Nullify(ref StringBuilder sb, string message)
{
    sb.Append(message);
    sb = null;
}

// -- snip --

StringBuilder sb = new StringBuilder();
string message = "Hi Guy";
Nullify(ref sb, message);
System.Console.WriteLine(sb.ToString());

// Output
// NullReferenceException

4

Ein als ref übergebenes Argument muss vor der Übergabe an die Methode initialisiert werden, während der out-Parameter vor der Übergabe an eine Methode nicht initialisiert werden muss.


4

warum willst du jemals verbrauchen?

Damit andere wissen, dass die Variable initialisiert wird, wenn sie von der aufgerufenen Methode zurückkehrt!

Wie oben erwähnt: "Für einen out-Parameter muss die aufrufende Methode einen Wert zuweisen, bevor die Methode zurückkehrt ."

Beispiel:

Car car;
SetUpCar(out car);
car.drive();  // You know car is initialized.

4

Grundsätzlich beides refund outzum Übergeben von Objekt / Wert zwischen Methoden

Das Schlüsselwort out bewirkt, dass Argumente als Referenz übergeben werden. Dies ist wie das Schlüsselwort ref, außer dass ref erfordert, dass die Variable initialisiert wird, bevor sie übergeben wird.

out : Das Argument ist nicht initialisiert und muss in der Methode initialisiert werden

ref : Das Argument ist bereits initialisiert und kann in der Methode gelesen und aktualisiert werden.

Was ist die Verwendung von "ref" für Referenztypen?

Sie können den angegebenen Verweis auf eine andere Instanz ändern.

Wusstest du?

  1. Obwohl die Schlüsselwörter ref und out ein unterschiedliches Laufzeitverhalten verursachen, werden sie zur Kompilierungszeit nicht als Teil der Methodensignatur betrachtet. Daher können Methoden nicht überladen werden, wenn der einzige Unterschied darin besteht, dass eine Methode ein ref-Argument und die andere ein out-Argument verwendet.

  2. Sie können die Schlüsselwörter ref und out nicht für die folgenden Arten von Methoden verwenden:

    • Asynchrone Methoden, die Sie mithilfe des Modifikators asynchron definieren.
    • Iterator-Methoden, die eine Yield Return- oder Yield Break-Anweisung enthalten.
  3. Eigenschaften sind keine Variablen und können daher nicht als Out-Parameter übergeben werden.


4

Zusätzliche Hinweise zu C # 7:
In C # 7 müssen Variablen nicht mit out vordeklariert werden. Also ein Code wie dieser:

public void PrintCoordinates(Point p)
{
  int x, y; // have to "predeclare"
  p.GetCoordinates(out x, out y);
  WriteLine($"({x}, {y})");
}

Kann so geschrieben werden:

public void PrintCoordinates(Point p)
{
  p.GetCoordinates(out int x, out int y);
  WriteLine($"({x}, {y})");
}

Quelle: Was ist neu in C # 7?


4

Ich habe immer noch das Bedürfnis nach einer guten Zusammenfassung, das habe ich mir ausgedacht.

Zusammenfassung,

Wenn wir uns innerhalb der Funktion befinden , geben wir auf diese Weise die Zugriffssteuerung für variable Daten an.

in = R.

out = muss W vor R.

ref = R + W.


Erläuterung,

in

Die Funktion darf nur diese Variable LESEN .

out

Variable muss nicht zuerst da, initialisiert werden
Funktion MUST WRITE , um es vor dem READ .

ref

Die Funktion kann diese Variable LESEN / SCHREIBEN .


Warum heißt es so?

Konzentrieren Sie sich darauf, wo Daten geändert werden.

in

Daten dürfen nur vor Eingabe der (In-) Funktion eingestellt werden.

out

Daten dürfen nur eingestellt werden, bevor die Funktion (out) verlassen wird.

ref

Die Daten müssen vor der Eingabe der (In-) Funktion eingestellt werden.
Daten können eingestellt werden, bevor die Funktion (out) verlassen wird.


Vielleicht sollte (in / out / ref) in (r / wr / rw) umbenannt werden. oder vielleicht auch nicht, rein / raus ist eine schönere Metapher.
Basteln

0

Es ist zu beachten, dass dies inein gültiges Schlüsselwort ab C # Version 7.2 ist :

Der Modifikator in parameter ist in C # 7.2 und höher verfügbar. Frühere Versionen erzeugen einen Compilerfehler CS8107 ("Die Funktion" Nur Lesezugriffe "ist in C # 7.0 nicht verfügbar. Bitte verwenden Sie die Sprachversion 7.2 oder höher.") Informationen zum Konfigurieren der Compilersprachenversion finden Sie unter Auswählen der C # -Sprachenversion.

...

Das Schlüsselwort in bewirkt, dass Argumente als Referenz übergeben werden. Es macht den formalen Parameter zu einem Alias ​​für das Argument, das eine Variable sein muss. Mit anderen Worten, jede Operation am Parameter wird für das Argument ausgeführt. Es ist wie die Schlüsselwörter ref oder out, außer dass in Argumente nicht durch die aufgerufene Methode geändert werden können. Während ref-Argumente geändert werden können, müssen out-Argumente durch die aufgerufene Methode geändert werden, und diese Änderungen können im aufrufenden Kontext beobachtet werden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.