Frage

Wenn ich ein Objekt an eine Methode übergeben habe, warum sollte ich das Ref -Keyword verwenden? Ist das nicht das Standardverhalten?

Zum Beispiel:

class Program
{
    static void Main(string[] args)
    {
        TestRef t = new TestRef();
        t.Something = "Foo";

        DoSomething(t);
        Console.WriteLine(t.Something);
    }

    static public void DoSomething(TestRef t)
    {
        t.Something = "Bar";
    }
}


public class TestRef
{
    public string Something { get; set; }
}

Die Ausgabe ist "Balken", was bedeutet, dass das Objekt als Referenz übergeben wurde.

War es hilfreich?

Lösung

Pass a ref Wenn Sie ändern möchten, was das Objekt ist:

TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);

void DoSomething(ref TestRef t)
{
  t = new TestRef();
  t.Something = "Not just a changed t, but a completely different TestRef object";
}

Nachdem ich Dosen angerufen hatte, t bezieht sich nicht auf das Original new TestRef, bezieht sich aber auf ein völlig anderes Objekt.

Dies kann auch nützlich sein, wenn Sie den Wert eines unveränderlichen Objekts ändern möchten, z. B. string. Sie können den Wert von a nicht ändern string Sobald es geschaffen wurde. Aber mit a ref, Sie können eine Funktion erstellen, die die Zeichenfolge für eine andere verändert, die einen anderen Wert hat.

Bearbeiten: Wie andere Leute erwähnt haben. Es ist keine gute Idee zu verwenden ref es sei denn, es wird benötigt. Verwendung ref Gibt der Methode Freiheit, das Argument für etwas anderes zu ändern. Anrufer der Methode müssen codiert werden, um sicherzustellen, dass sie diese Möglichkeit bewältigen.

Wenn der Parametertyp ein Objekt ist, wirken Objektvariablen immer als Verweise auf das Objekt. Dies bedeutet, dass wenn die ref Schlüsselwort wird verwendet. Sie haben einen Verweis auf eine Referenz. Auf diese Weise können Sie Dinge wie in dem oben angegebenen Beispiel tun. Aber wenn der Parametertyp ein primitiver Wert ist (z. B. int), wenn dieser Parameter innerhalb der Methode zugewiesen wird, wird der Wert des Arguments, das in übergeben wurde, nach Rückgabe der Methode geändert:

int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10

void Change(ref int x)
{
  x = 5;
}

void WillNotChange(int x)
{
  x = 10;
}

Andere Tipps

Sie müssen zwischen "eine Referenz nach Wert bestehen" und "einen Parameter/Argument durch Referenz" unterscheiden.

Ich habe a geschrieben Einigermaßen langer Artikel zu diesem Thema Um nicht jedes Mal, wenn dies auf Newsgroups zu sehen ist, sorgfältig schreiben zu müssen :)

In .NET Wenn Sie einen Parameter an eine Methode übergeben, wird eine Kopie erstellt. Bei Werttypen bedeutet jede Änderung, die Sie am Wert vornehmen, im Methodenbereich und beim Beenden der Methode verloren.

Beim Übergeben eines Referenztyps wird auch eine Kopie durchgeführt, aber es handelt sich um eine Kopie einer Referenz, dh jetzt haben Sie zwei Referenzen im Speicher auf dasselbe Objekt. Wenn Sie also die Referenz verwenden, um das Objekt zu ändern, wird es geändert. Wenn Sie jedoch die Referenz selbst ändern - wir müssen uns daran erinnern, dass es sich um eine Kopie handelt - dann gehen auch Änderungen beim Verlassen der Methode verloren.

Wie die Menschen bereits gesagt haben, ist eine Aufgabe eine Änderung der Referenz und ist daher verloren:

public void Method1(object obj) {   
 obj = new Object(); 
}

public void Method2(object obj) {  
 obj = _privateObject; 
}

Die obigen Methoden verändern das ursprüngliche Objekt nicht.

Eine kleine Änderung Ihres Beispiels

 using System;

    class Program
        {
            static void Main(string[] args)
            {
                TestRef t = new TestRef();
                t.Something = "Foo";

                DoSomething(t);
                Console.WriteLine(t.Something);

            }

            static public void DoSomething(TestRef t)
            {
                t = new TestRef();
                t.Something = "Bar";
            }
        }



    public class TestRef
    {
    private string s;
        public string Something 
        { 
            get {return s;} 
            set { s = value; }
        }
    }

Da TestRef eine Klasse ist (die Referenzobjekte sind), können Sie den Inhalt in T ändern, ohne ihn als Ref zugeben. Wenn Sie jedoch T als Ref bestanden, kann TestRef ändern, worauf sich das ursprüngliche T bezieht. dh es auf ein anderes Objekt hinweisen.

Mit ref Du kannst schreiben:

static public void DoSomething(ref TestRef t)
{
    t = new TestRef();
}

Und T wird nach Abschluss der Methode geändert.

Denken Sie an Variablen (zB foo) von Referenztypen (z. B. List<T>) als Holding Objektkennung des Formulars "Objekt #24601". Angenommen, die Aussage foo = new List<int> {1,5,7,9}; Ursachen foo So halten Sie "Objekt #24601" (eine Liste mit vier Elementen). Dann rufe foo.Length fragt das Objekt #24601 nach seiner Länge und es wird 4 antworten, also foo.Length wird gleich 4.

Wenn foo wird an eine Methode übergeben, ohne zu verwenden ref, Diese Methode kann Änderungen an Objekt #24601 vornehmen. Infolge solcher Veränderungen,, foo.Length Möglicherweise nicht mehr gleich 4. Die Methode selbst kann sich jedoch nicht ändern foo, die weiterhin "Objekt #24601" enthalten.

Vorbeigehen foo Als ein ref Der Parameter ermöglicht es der aufgerufenen Methode, Änderungen nicht nur an Objekt Nr. 24601, sondern auch an vorzunehmen foo selbst. Die Methode kann ein neues Objekt #8675309 erstellen und einen Verweis auf das in speichern foo. Wenn dies der Fall ist, foo würde nicht mehr "Objekt #24601" halten, sondern "Objekt #8675309".

In der Praxis halten Referenzvariablen keine Zeichenfolgen des Formulars "Objekt #8675309". Sie halten nicht einmal etwas, das sinnvoll in eine Zahl umgewandelt werden kann. Obwohl jede Referenzvariable ein bisschen Bitmuster enthält, gibt es keine feste Beziehung zwischen den Bitmustern, die in solchen Variablen gespeichert sind, und den von ihnen identifizierten Objekten. Es gibt keine Möglichkeit, dass Code Informationen aus einem Objekt oder einer Referenz darauf extrahieren kann, und später feststellen, ob eine andere Referenz dasselbe Objekt identifizierte, es sei denn, der Code enthielt oder wusste eine Referenz, die das ursprüngliche Objekt identifizierte.

Dies ist so, als würde man einen Zeiger an einen Zeiger in C in .NET übergeben. Auf diese Weise können Sie ändern, worauf sich das ursprüngliche T bezieht. persönlich Obwohl ich denke, wenn Sie das in .NET tun, haben Sie wahrscheinlich ein Designproblem!

Durch Verwendung der ref Schlüsselwort mit Referenztypen Sie übergeben effektiv eine Referenz auf die Referenz. In vielerlei Hinsicht ist es dasselbe wie die Verwendung der out Schlüsselwort, aber mit dem geringfügigen Unterschied, dass es keine Garantie gibt, dass die Methode dem tatsächlich etwas zuweist ref'Ed Parameter.

ref Mimics (oder verhält sich verhält) als globaler Bereich nur für zwei Bereiche:

  • Anrufer
  • Callee.

Wenn Sie jedoch einen Wert geben, sind die Dinge unterschiedlich. Sie können einen Wert erzwingen, der mit Referenz übergeben wird. Auf diese Weise können Sie beispielsweise eine Ganzzahl an eine Methode übergeben und die Methode die Ganzzahl in Ihrem Namen ändern lassen.

Ref bezeichnet, ob die Funktion das Objekt selbst oder nur ihren Wert auf das Objekt erheben kann.

Das Bestehen von Referenzen ist nicht an eine Sprache gebunden; Es handelt sich um eine Parameterbindungsstrategie neben Pass-by-Wert, Pass mit Namen, Pass für Bedürfnisse usw.

Eine Nebenbetreuung: der Klassenname TestRef ist eine schrecklich schlechte Wahl in diesem Zusammenhang;).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top