ref Frage

Reverent

Erfahrenes Mitglied
Hallo Leute,
ich bin beim Lesen MSDN auf dies gestoßen:
Das Festlegen des ref-Schlüsselworts für Methodenparameter führt dazu, dass eine Methode auf dieselbe Variable verweist, die in die Methode übergeben wurde. Alle Änderungen des Methodenparameters werden in diese Variable übernommen, sobald die Steuerung wieder an die aufrufende Methode übergeben wird.

Um einen ref-Parameter verwenden zu können, muss das Argument explizit als ref-Argument an die Methode übergeben werden. Der Wert des ref-Arguments wird an den ref-Parameter übergeben.

Ein Argument, das an einen ref-Parameter übergeben wird, muss zunächst initialisiert werden. Einen Vergleich bietet der out-Parameter, dessen Argument nicht explizit initialisiert werden muss, bevor er an den out-Parameter übergeben wird.

Eine Eigenschaft stellt keine Variable dar und kann nicht als ref-Parameter übergeben werden.

Wenn sich die Deklarationen von zwei Methoden lediglich in der Verwendung von ref unterscheiden, tritt eine Überladung auf. Es kann jedoch keine Überladung definiert werden, die sich lediglich hinsichtlich der Verwendung von ref anstelle von out und umgekehrt unterscheidet. Die folgenden Überladungsdeklarationen sind beispielsweise gültig:
Code:
// cs_ref.cs
using System;
public class MyClass 
{
   public static void TestRef(ref char i) 
   {
      // The value of i will be changed in the calling method
      i = 'b';
   }

   public static void TestNoRef(char i) 
   {
      // The value of i will be unchanged in the calling method
      i = 'c';
   }

   // This method passes a variable as a ref parameter; the value of the 
   // variable is changed after control passes back to this method.
   // The same variable is passed as a value parameter; the value of the
   // variable is unchanged after control is passed back to this method.
   public static void Main() 
   {
   
      char i = 'a';    // variable must be initialized
      TestRef(ref i);  // the arg must be passed as ref
      Console.WriteLine(i);
      TestNoRef(i);
      Console.WriteLine(i);
   }
}
Ausgabe:
b
b

Ich habe mir das mehrmals durchgelesen aber ich kappiere das nicht, hat einer verständlichere Worte?
Wenn ich wüsste wofür man das braucht wäre ich vielleicht schon schlauer.
BisDann
 
Ich finde den Text eigentlich recht verstaendlich, versuche es aber mal einfacher zu formulieren:

Wenn du einen Parameter mittels "ref" uebergibst, kann der uebergeben Wert in der aufgerufenen Methode geaendert werden. Du kannst dir es so vorstellen, dass theoretisch ein Zeiger auf den Wert uebergeben wird, wenn du hingegen ohne ref arbeitest wird der Wert kopiert. Der urspruengliche Wert der uebergebenen Variable kann dabei aber nicht veraendert werden.

Der Unterschied zwischen out und ref ist lediglich, dass ref-Parameter bei der Uebergabe schon initialisiert sein muessen, out-Parameter aber nicht. Ausserdem ist es moeglich eine Methode zu ueberladen, indem man bei den Parametern nur ein ref hinzufuegt. EIne Methode aber durch den Unterschied zu out und ref zu ueberladen ist hingegen nicht moeglich.

Das Beispielprogramm laeuft folgendermassen ab:
'i' wird als 'a' initalisiert und der Methode mit dem ref-Parameter uebergeben. In der Methode wird nun der Wert von 'i' veraendert. Da es als Referenz uebergeben wurde, wirkt diese Aenderung auch auf die urspruengliche Variable 'i' der Main-Methode.
In der naechsten Methode wird 'i' auf 'c' geaendert, da es aber nicht als ref uebergeben wurde, ist die Aenderung nur innerhalb des Methodenrumpfes gueltig. Auf die Variable in der Main-Methode hat sie keine Auswirkung, die bleibt 'b'.

Wofuer du es brauchst? Ich persoenlich habe out/ref noch nicht allzu oft gebraucht, allerdings ist es nuetzlich wenn eine Methode mehrere Werte zurueckgeben muss. Dabei musst du dich dann eben nicht auf den Methodenrueckgabetyp beschraenken, sondern kannst die anderen Sachen per ref/out uebergeben.
 
cosmochaosmaker hat gesagt.:
OMG diese Definition aus der MSDN ist absoluter Schwachsinn.
Absolut Zielfremd. :rolleyes:
Daraus geht kein bissel hervor wo man was benötigt.

Naaaja, absoluten Schwachsinn würde ich etwas anderes Bezeichnen, aber egal.

Wenn über ref und out gesprochen wird, sollte mal allen klar sein wie in .net Datentypen aufgeteilt sind und wie es jeweils mit der Übergabe an Methoden aussieht.

Arten: Referenztypen (Klassen), Werttypen (Strukturen, und damit alle primitiven Datentypen wie int etc. (Sind ja auch nur nur Strukturen))

Bei Referenztypen wird in der Variable nur eine Referenz auf ein Objekt gespeichert!
Werttypen enthalten direkt den Wert.

Wird bei Referenztypen zugewiesen wird immer eine Referenzkopie gemacht die auf das slebe Objekt zeigt. Bei Werttypen wird der Wert kopiert. Das spiegelt sich dann bei Methodenaufrufen wieder!

Methodenaufrufe sind normalerweise call-by-value. Von den Parametern werden Kopien erstellt und diese übergeben. Bei Referenztypen wird die Referenz kopiert, zeigt also noch immer aufs selbe Objekt (Siehe Referenzen in C++). Bei Werttypen ist das anders.
Dort sind die Werte in und ausserhalb der Aufgerufenen Methode getrennt. (Eben weil eine Kopie erzeugt wurde)

Die Schlüsselwörter ref und out beeinflussen diese Verhalten! Durch ref wird ein call-by-reference durchgeführt, es wird also keine Kopie erzeugt. Die übergebene Variable muss aber bereits erzeugt sein/einen Wert haben.
Mit out lassen sich Ausgangsparameter erzeugen. Die Übergabe ist wieder call-by-reference, aber die übergebene Variable muss noch keinen Wert haben.

Bei C++ ist das schön durch den Copy-Konstruktor zu sehen.
Die Ausgabe vom folgenden C++ Programm ist:
1: ctor_a
2: cctor_a
3: writeContent: huhu
4: writeContentRef: huhu

Die Nummerierungen oben hab ich unten als Kommentare drinnen.

Code:
#include <iostream>
#include <string>

using std::cout;
using std::cin;
using std::endl;
using std::string;

class A
{
  private:
    string content;
    
    
  public:
    A(string c);
    A(A const &copy);
    string getContent() const;
};

void writeContent(A const a);
void writeContentRef(A const& a);

int main()
{
  A otto("huhu"); // 1
  
  writeContent(otto); // 2 (Kopie wird erstellt)
  writeContentRef(otto);
  
  return 0;
}

void writeContent(A const a)
{
  cout << "writeContent: " << a.getContent() << endl; // 3, die Kopie
}

void writeContentRef(A const &a)
{
    cout << "writeContentRef: " << a.getContent() << endl; // 4 - keine Kopie!
}

A::A(string c) : content(c)
{
  cout << "ctor_a" << endl;
}

A::A(A const &copy) : content(copy.getContent())
{
  cout << "cctor_a" << endl;
}

string A::getContent() const
{
  return content;
}

Das folgende C# Beispiel könnts euch ja auch ansehen.

Code:
using System;

namespace CopyTest
{
	class Class1
	{
		[STAThread]
		static unsafe void Main(string[] args)
		{
			Test t = new Test("initial wert");

			Console.WriteLine("1: {0}", t.Text);
		
			change2(t);

			Console.WriteLine("2: {0}", t.Text);

			change1(ref t);

			Console.WriteLine("3: {0}", t.Text);

			int test = 100;

			c1(ref test);

			Console.WriteLine("call c1, 1: {0}", test);

			c2(test);

			Console.WriteLine("call c2, 1: {0}", test);

			c3(test);

			Console.WriteLine("call c3, 1: {0}", test);

			c2(test);

			Console.WriteLine("call c2, 2: {0}", test);

			c1(ref test);

			Console.WriteLine("call c1, 2: {0}", test);

			c3(test);

			Console.WriteLine("call c3, 2: {0}", test);

			Console.Read();
			Console.Read();

		}

		private unsafe static void c1(ref int test)
		{
			test = test*2;
		
			fixed (int* t = &test)
			{
				Console.WriteLine("Adresse: {0:x}", (int)t);
			}
		}

		private unsafe static void c2(int test)
		{
			test = test*2;
			int* t = &test;
			Console.WriteLine("Adresse: {0:x}", (int)t);
		}

		private unsafe static void c3(int test)
		{
			test = test*2;
			int* t = &test;
			Console.WriteLine("Adresse: {0:x}", (int)t);
		}

		private unsafe static void change1(ref Test test)
		{
			test.Text = "REF";
			Console.WriteLine("Changed to REF");
		}

		private unsafe static void change2(Test test)
		{
			test.Text = "NON REF";
			Console.WriteLine("Changed to NON REF");
		}
	}

	public class Test
	{
		private string text;
		public string Text { get { return text;} set { text = value; } }


		public Test (string text)
		{
			this.text = text;

			Console.WriteLine("ctor_test");
		}
	}
}
 
Dank sei auch Dir Alexander Schuc,
die Übergabe per ref kann ich das mit einer Zeigerübergabe in C vergleichen?
Bis Dann
 
Ja. Ist halt call-by-reference statt call-by-value
Besserer Vergleich ist halt die Referenzübergabe aus C++

Und bitte, schreib nicht immer meinen vollen Namen. Alex, Wiesel, Alexander.. irgendwas davon reicht.
 

Neue Beiträge

Zurück