Verwenden der Schlüsselwörter REF und OUT mit Passing by Reference und Passing by Value in C#

StackOverflow https://stackoverflow.com/questions/1683394

  •  18-09-2019
  •  | 
  •  

Frage

Folgendes verstehe ich bisher:

WERTE ÜBERGEBEN

Die Übergabe als Wert bedeutet, dass eine Kopie eines Arguments übergeben wird.Änderungen an dieser Kopie haben keine Auswirkungen auf das Original.

PASS BY REFERENZ

Unter Referenzübergabe versteht man, dass eine Referenz auf das Original übergeben wird.Änderungen an der Referenz wirken sich auf das Original aus.

REF-Schlüsselwort

REF teilt dem Compiler mit, dass das Objekt initialisiert wird, bevor die Funktion eingegeben wird.REF bedeutet, dass der Wert bereits festgelegt ist und die Methode ihn daher lesen und ändern kann.REF hat zwei Möglichkeiten, sowohl rein als auch raus.

OUT-Schlüsselwort

OUT teilt dem Compiler mit, dass das Objekt innerhalb der Funktion initialisiert wird.OUT bedeutet, dass der Wert noch nicht festgelegt ist und daher vor dem Aufruf von return festgelegt werden muss.OUT ist nur ein Weg, nämlich raus.

Frage

In welchen Szenarien würden Sie also die Verwendung der Schlüsselwörter „ref“ und „out“ mit der Übergabe als Referenz oder der Übergabe als Wert kombinieren?Beispiele würden enorm helfen.

Hilfe sehr geschätzt.

War es hilfreich?

Lösung

Sie würden nie ref und out auf 1 Parameter kombinieren. Beide bedeuten 'Pass by reference'.

Sie können natürlich ref Parameter und out-Parameter in einem Verfahren kombinieren.

Der Unterschied zwischen ref und out liegt vor allem in der Absicht . ref Signale 2-Wege-Datentransportmittel aus 1-Weg.

Aber neben der Absicht, der C # -Compiler verfolgt definitive Zuweisung und das macht die meisten spürbaren Unterschied. Es verhindert auch den Missbrauch (Lesen) ein out-Parameter.

void SetOne(out int x) 
{
  int y = x + 1; // error, 'x' not definitely assigned.
  x = 1;         // mandatory to assign something
}

void AddTwo(ref int x)
{
    x = x + 2;  // OK, x  is known to be assigned
}

void Main()
{
    int foo, bar;

    SetOne(out foo); // OK, foo does not have to be assigned
    AddTwo(ref foo); // OK, foo assigned by SetOne
    AddTwo(ref bar); // error, bar is unassigned
}

Andere Tipps

Hilfe sehr geschätzt

Ihr Verständnis wird durch einen korrekten und sorgfältigen Sprachgebrauch verbessert.

Die Übergabe als Wert bedeutet, dass eine Kopie eines Arguments übergeben wird.

Ja, das ist genau richtig.

Änderungen an dieser Kopie haben keine Auswirkungen auf das Original.

Nicht genau.Beginnen Sie mit einer sorgfältigen Unterscheidung Werte Und Variablen.Halten:

class Foo { public int x; }
...
void N() 
{
  Foo blah = new Foo();
  blah.x = 0;
  M(blah);
}
...
void M(Foo foo)
{
  foo.x = 123; // changes blah.x
  foo = null; // does not change blah
}

Die Variablen hier sind x, blah und foo.x ist ein Feld, blah ist ein lokaler Parameter, foo ist ein formaler Parameter.

Die Werte hier sind null, 0, 123 und ein Verweis auf eine Instanz von Foo. Diese Referenz ist ein Wert. Es ist wichtig, diese Tatsache zu verstehen.

Eine Kopie des Wertes von blah wird übergeben, indem der Wert der Variablen blah in die Variable foo kopiert wird.Der Wert von blah ist ein Verweis auf die Instanz von Foo.

M kann den Wert der Variablen x ändern, da M eine Kopie des Werts von blah hat, der eine Referenz auf ein Foo ist.Wenn M den Inhalt von foo in null ändert, ändert sich daran nichts, blah;foo enthält eine Kopie des Wertes von blah.

Unter Referenzübergabe versteht man, dass eine Referenz auf das Original übergeben wird.

Wählen Sie Ihre Formulierung sorgfältig aus.Was ist „das Original“?

Dies wäre besser ausgedrückt als „Übergabe als Referenz bedeutet, dass eine Referenz auf das Argument, das eine Variable sein muss, übergeben wird“.Eine einfachere Möglichkeit, darüber nachzudenken, besteht darin, dass „die Übergabe als Referenz den Parameter zu einem Alias ​​für die als Argument übergebene Variable macht“.

Änderungen an der Referenz wirken sich auf das Original aus.

Da der Parameter und das Argument Aliase füreinander sind, wirken sich Änderungen an der Referenz nicht auf das Original aus;Die Referenz ist das Original.Beide sind die gleiche Variable.

REF teilt dem Compiler mit, dass das Objekt initialisiert wird, bevor die Funktion eingegeben wird.

„Das Objekt“ ist bedeutungslos.Du meinst „die Variable“.

„ref“ teilt dem Compiler nicht mit, dass die Variable initialisiert ist.Vielmehr teilt „ref“ dem Compiler mit, dass „Sie, Compiler, überprüfen müssen, ob die Variable initialisiert ist“.Das ist schon etwas anderes!

REF bedeutet, dass der Wert bereits festgelegt ist.

Nein, Ref erfordert, dass die Variable ist bereits eingestellt.So etwas wie „einen Wert festlegen“ gibt es nicht.

Die Methode kann es daher lesen und ändern.

Wobei mit „es“ „die Variable“ gemeint ist.

REF hat zwei Möglichkeiten, sowohl rein als auch raus.

Richtig.

OUT teilt dem Compiler mit, dass das Objekt innerhalb der Funktion initialisiert wird.

Hören Sie auf, „das Objekt“ in der Bedeutung „die Variable“ zu verwenden.Sie werden die Dinge viel klarer verstehen, wenn Sie aufhören, völlig unterschiedliche Dinge durcheinander zu bringen. Variablen sind keine Objekte. Variablen sind Speicherorte einige davon könnten enthalten Werte, und einige dieser Werte könnten es sein Verweise auf Objekte.

Out teilt dem Compiler also mit, dass die Variable innerhalb der Methode initialisiert wird, ja, aber das ist nicht ganz richtig.Sie vergessen die Fälle, in denen die Methode eine Ausnahme auslöst oder in eine Endlosschleife gerät – auch das sind zulässige Szenarien.

OUT bedeutet, dass der Wert noch nicht festgelegt ist.

Auch hier meinen Sie mit „dem Wert“ „die Variable“.Aber das ist nicht korrekt.Es ist völlig legal, eine initialisierte Variable als „out“-Parameter zu übergeben.Sinnlos, aber legal.

und muss daher vor dem Aufruf von return gesetzt werden.

„Rückkehr“ heißt nicht;Methoden aufgerufen werden.Aber ja, die Methode muss der Variablen einen Wert zuweisen, bevor sie normal zurückkehrt.

OUT ist nur ein Weg, nämlich raus.

Rechts.

In welchen Szenarien würden Sie also die Verwendung der Schlüsselwörter ref und out kombinieren?

Solche Szenarien gibt es nicht.

Sie verstehen die Dynamik der so oder so vorbei. Einige Parameter Szenarien könnten sein:

  • ref int num für ein in / out-Parameter. Die Funktion können Ändern Sie den Wert darin.
  • out int num wie ref außer Funktion muss einen Wert zu vor der Rückkehr zu.

Im allgemeinen Ausgangsparameter sind gut für die, wenn eine Funktion mehrere Werte zurückgeben muss, da eine Funktion nur einen Rückgabewert hat (obwohl es Verbindung sein kann).

Manchmal Datenzugangsanbieter, wie einige ADO.NET Methoden, Ausgabeparameter verwenden, um Informationen zurück zu liefern. Einige Datenzugriffsmethoden imitieren Datenbank gespeicherte Prozeduren, die in / out-Parameter haben.

Edit: Eine Bedingung für Referenztypen ist die Parameter ref StringBuilder word oder StringBuilder word (nach Wert) verhält sich das gleiche - die Zeichenfolge außerhalb betroffen sind, obwohl der zugrunde liegende implementatoin weil etwas an diesem Punkt unterscheiden kann der Fokus die Referenz und nicht der Wert auf dem Heap.

Edit: Ich habe diese Antwort korrigiert zu reflektieren, dass das ‚out‘ Schlüsselwort in C # nicht tut, was Sie es (zB einem wahren OUT-Parameter in der Informatik Sinne des Wortes erwarten ). Ich erklärte, ursprünglich, dass ‚out‘ Pass war OUT von Wert wurde aber als falsch erwiesen.

Sie können nicht und ‚ref‘ zusammen verwenden ‚out‘. Es gibt drei Aufrufkonventionen in C # (.NET Framework):

  • Keine keyword = Pass nach Wert (IN)
  • 'out' Schlagwort = Pass durch Referenz (REF) ohne eindeutige Zuordnung Anforderung vor Aufruf
  • 'ref' Stichwort = Pass durch Referenz (REF) mit einer bestimmten Zuordnung Anforderung vor Aufruf

C # hat keine wahre OUT oder IN-OUT-Parameter Fähigkeit.

Um zu sehen, dass 'out' Parameter in C # sind nicht wahr OUT-Parameter, können Sie den folgenden Code verwenden:

  public class Test
  {
    Action _showValue;

    public void Run()
    {
      string local = "Initial";
      _showValue = () => { Console.WriteLine(local.ToString()); };

      Console.WriteLine("Passing by value");
      inMethod(local);

      Console.WriteLine("Passing by reference with 'out' keyword");
      outMethod(out local);

      Console.WriteLine("Passing by reference with 'ref' keyword");
      refMethod(ref local);

    }

    void inMethod(string arg)
    {
      _showValue();
      arg = "IN";
      _showValue();
    }

    void outMethod(out string arg)
    {
      _showValue();
      arg = "OUT";
      _showValue();
    }

    void refMethod(ref string arg)
    {
      _showValue();
      arg = "REF";
      _showValue();
    }
  }

Die Ausgabe lautet:

Passing by value
Initial
Initial
Passing by reference with 'out' keyword
Initial
OUT
Passing by reference with 'ref' keyword
OUT
REF

Wie Sie sehen können, beide ‚out‘ und ‚ref‘ passiert tatsächlich durch REF. Der einzige Unterschied besteht darin, wie die Compiler sich für eindeutige Zuordnung Zwecke behandelt.

das OUT Schlüsselwort ist nützlich, wenn Sie eine Methode, die Sie brauchen mehr als einen Wert zurückgeben. Zum Beispiel sehen Sie Methoden wie int.TryParse().

REF Verwendung mehr für Eindeutigkeit von Objekten. Unter Berücksichtigung der Tatsache, dass jede nicht-primitive in eine Methode übergeben von Natur aus durch Referenz übergeben wird ist es nicht viel Bedarf für ihn in der normalen verwalteten Code. Durch die Deklaration des REF Schlüsselwort Sie besagt, dass der Parameter wird wahrscheinlich in den Körper des Verfahrens modifiziert werden und somit sollte der Angerufene Code sich dessen bewusst sein (also, warum Sie müssen explizit die ref im rufenden Code hinzufügen, auch.

Wenn Sie c verstehen ++ vielleicht dies wird Ihnen helfen:

void Foo(Bar) {} // pass by value c# (if it's a value type ;))
void Foo(Bar) {} // c++

void Foo(Bar) {} // pass by reference c# (if it's a reference type ;))
void Foo(Bar&) {} // c++

void Foo(ref Bar) {} // c#
void Foo(Bar*) // c++

void Foo(out Bar) {} // c#
void Foo(Bar**) {} // c++ (the contents of *Bar needs to be filled up)

Sie passieren ref etwas, was Sie wollen durch eine andere Funktion gelesen und geschrieben werden, so dass Sie die Variable initialisiert, um passieren sollte korrekt gelesen werden.

EDIT: Beispiel:

void mymethod(ref int a) {
  a++;
}

Sie übergeben als OUT etwas, das man durch eine andere Funktion geschrieben werden wollen, aber Sie brauchen es nicht initialisiert werden, da es nicht durch die Funktion, nur geschrieben gelesen werden.

EDIT: Beispiel:

void mymethod2(out string a) {
  a="hello";
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top