webentwicklung-frage-antwort-db.com.de

Was ist die Verwendung von "ref" für Variablen vom Referenztyp in C #?

Ich verstehe, dass, wenn ich einen Werttyp (int, struct usw.) als Parameter (ohne das Schlüsselwort ref) übergebe, eine Kopie dieser Variablen übergeben wird an die Methode, aber wenn ich das Schlüsselwort ref verwende, wird ein Verweis auf diese Variable übergeben, kein neuer.

Bei Referenztypen wie Klassen wird jedoch auch ohne das Schlüsselwort ref eine Referenz an die Methode und keine Kopie übergeben. Wozu dient also das Schlüsselwort ref mit Referenztypen?


Nehmen Sie zum Beispiel:

var x = new Foo();

Was ist der Unterschied zwischen den folgenden?

void Bar(Foo y) {
    y.Name = "2";
}

und

void Bar(ref Foo y) {
    y.Name = "2";
}
164
Andreas Grech

Sie können ändern, worauf foo zeigt, indem Sie y verwenden:

Foo foo = new Foo("1");

void Bar(ref Foo y)
{
    y = new Foo("2");
}

Bar(ref foo);
// foo.Name == "2"
148
user7116

Es gibt Fälle, in denen Sie das aktuelle Referenz und nicht das Objekt ändern möchten, auf das verwiesen wird:

void Swap<T>(ref T x, ref T y) {
    T t = x;
    x = y;
    y = t;
}

var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);
29
Mehrdad Afshari

Jon Skeet schrieb ein großartiger Artikel über die Parameterübergabe in C #. Hier wird das genaue Verhalten und die Verwendung von Übergabeparametern nach Wert, Referenz (ref) und Ausgabe (out) genau beschrieben.

Hier ist ein wichtiges Zitat von dieser Seite in Bezug auf ref Parameter:

Referenzparameter übergeben nicht die Werte der Variablen, die beim Aufruf des Funktionsmembers verwendet wurden - sie verwenden die Variablen selbst. Anstatt einen neuen Speicherort für die Variable in der Funktionsmemberdeklaration zu erstellen, wird derselbe Speicherort verwendet, sodass der Wert der Variablen im Funktionsmember und der Wert des Referenzparameters immer gleich sind. Referenzparameter benötigen den Modifizierer ref als Teil der Deklaration und des Aufrufs. Das bedeutet, dass immer klar ist, ob Sie etwas als Referenz übergeben.

17
Noldorin

Sehr schön erklärt hier: http://msdn.Microsoft.com/en-us/library/s6938f28.aspx

Auszug aus dem Artikel:

Eine Variable eines Referenztyps enthält ihre Daten nicht direkt. es enthält einen Verweis auf seine Daten. Wenn Sie einen Parameter vom Typ Referenz als Wert übergeben, können Sie die Daten ändern, auf die die Referenz verweist, z. B. den Wert eines Klassenmitglieds. Der Wert der Referenz selbst kann jedoch nicht geändert werden. Das heißt, Sie können denselben Verweis nicht verwenden, um Speicher für eine neue Klasse zuzuweisen, und ihn außerhalb des Blocks beibehalten. Übergeben Sie dazu den Parameter mit dem Schlüsselwort ref oder out.

15

Wenn Sie einen Referenztyp mit dem Schlüsselwort ref übergeben, übergeben Sie die Referenz als Referenz, und die aufgerufene Methode kann dem Parameter einen neuen Wert zuweisen. Diese Änderung wird an den aufrufenden Bereich weitergegeben. Ohne ref wird die Referenz als Wert übergeben, und das passiert nicht.

C # hat auch das Schlüsselwort 'out', das dem Schlüsselwort ref sehr ähnlich ist, außer dass bei 'ref' die Argumente vor dem Aufruf der Methode initialisiert werden müssen, und bei 'out' müssen Sie der empfangenden Methode einen Wert zuweisen.

9
Rytmis

Hiermit können Sie die übergebene Referenz ändern.

void Bar()
{
    var y = new Foo();
    Baz(ref y);
}

void Baz(ref Foo y)
{
    y.Name = "2";

    // Overwrite the reference
    y = new Foo();
}

Sie können auch out verwenden, wenn Sie sich nicht für die übergebene Referenz interessieren:

void Bar()
{
    var y = new Foo();
    Baz(out y);
}

void Baz(out Foo y)
{
    // Return a new reference
    y = new Foo();
}
5
HVS

Ein weiterer Haufen Code

class O
{
    public int prop = 0;
}

class Program
{
    static void Main(string[] args)
    {
        O o1 = new O();
        o1.prop = 1;

        O o2 = new O();
        o2.prop = 2;

        o1modifier(o1);
        o2modifier(ref o2);

        Console.WriteLine("1 : " + o1.prop.ToString());
        Console.WriteLine("2 : " + o2.prop.ToString());
        Console.ReadLine();
    }

    static void o1modifier(O o)
    {
        o = new O();
        o.prop = 3;
    }

    static void o2modifier(ref O o)
    {
        o = new O();
        o.prop = 4;
    }
}
4
Svend

Zusätzlich zu den vorhandenen Antworten:

Wie Sie nach dem Unterschied der beiden Methoden gefragt haben: Bei Verwendung von ref oder out gibt es keine Co- (Ntra-) Varianz:

class Foo { }
class FooBar : Foo { }

static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }

void Main()
{
    Foo foo = null;
    Bar(foo);           // OK
    Bar(ref foo);       // OK

    FooBar fooBar = null;
    Bar(fooBar);        // OK (covariance)
    Bar(ref fooBar);    // compile time error
}
3
springy76

Ein Parameter in einer Methode scheint immer eine Kopie zu übergeben, die Frage ist eine Kopie von was. Eine Kopie wird von einem Kopierkonstruktor für ein Objekt erstellt, und da alle Variablen in C # Object sind, glaube ich, dass dies für alle der Fall ist. Variablen (Objekte) sind wie Menschen, die an bestimmten Adressen leben. Entweder ändern wir die Personen, die an diesen Adressen leben, oder wir können weitere Verweise auf die Personen, die an diesen Adressen leben, im Telefonbuch erstellen (flache Kopien erstellen). Somit kann sich mehr als ein Bezeichner auf dieselbe Adresse beziehen. Referenztypen benötigen mehr Speicherplatz. Im Gegensatz zu Werttypen, die durch einen Pfeil mit ihrem Bezeichner im Stapel verbunden sind, haben sie einen Wert für eine andere Adresse im Heap (mehr Speicherplatz zum Verweilen). Dieser Raum muss vom Haufen genommen werden.

Wertetyp: Kennung (enthält Wert = Adresse des Stapelwerts) ----> Wert des Wertetyps

Referenztyp: Bezeichner (enthält Wert = Adresse des Stack-Werts) ----> (enthält Wert = Adresse des Heap-Werts) ----> Heap-Wert (enthält meist Adressen zu anderen Werten), stellen Sie sich mehr Pfeile vor, die in verschiedenen Werten stecken Richtungen zu Array [0], Array [1], Array [2]

Die einzige Möglichkeit, einen Wert zu ändern, besteht darin, den Pfeilen zu folgen. Wenn ein Pfeil in der Weise verloren geht/geändert wird, ist der Wert nicht erreichbar.

1
Petar Drianov