ref's



  • Hallo,

    ich experimentiere gerade ein bisschen mit ref und out herum und stehe vor folgendem Problem:

    Einer Klasse Class1 übergebe ich im Konstruktor eine Vaiable aus Main() mittels ref. Jetzt will ich mir diese Referenz in Class1 merken um sie ggf. später so zu ändern, dass Main() diese Änderung mitbekommt.

    public class Class1
    {
      private int num;
      public Class1(ref int num)
      {
         this.num = num; # hier will ich mir die Referenz merken, nicht den Wert
      }
    
      public incNum()
      {
         num++; # hier soll eigentlich die Referenzvariable aus dem Konstruktor
                # erhöht werden.
      }
    }
    
    public static void Main()
    {
      int n = 5;
      Class1 c = new Class1(ref n);
      c.incNum();
      Console.Writeln(n);
    }
    

    Die Ausgabe sollte nun 6 sein; ist sie aber nicht.
    Was muß ich ändern?

    😕
    Gruß CS



  • Hi!

    Du erzeugst im Ctor der Klasse eine Kopie (this.num = num). Bau dir eine Funktion die dir den aktuellen Wert zurückliefert oder mach es so:

    static public void incNum(ref int num)
    {
    	++num;	// hier soll eigentlich die Referenzvariable aus dem Konstruktor
    		// erhöht werden.
    }
    
    /// <summary>
    /// Der Haupteinstiegspunkt für die Anwendung.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
    	int n = 5;
    	incNum(ref n);
    	Console.WriteLine(n);
    }
    

    Ich habe einfach nur eine Methode geschrieben und in dieser die Variable um 1 erhöht, wodurch die Originalvariable verändert wurde.

    Code-Hacker



  • Es würde auch noch gehen, wenn du den Wert in einen Wrapper hülst und dann den Wrapper übergibst.



  • Naja, die Funktion, die den Wert ändern soll, läuft in einem anderen Thread:

    public class RetThread
    {
      bool flag;
      public RetThread(ref bool flag)
      {
        this.flag = flag;
        new Thread(new ThreadStart(this.ThreadFunc)).Start();		
      }
    
      private void ThreadFunc()
      {
        flag=false;
        doNotSoImportantThings();
        flag=true;
      }
    }
    
    ...
    
    public class Class1
    {
       bool fertig=false;
       RetThread myThread = new RetThread(ref fertig);
       while (!flag)
      {
         doImportantThings();
      }
    }
    

    Die Main() läuft also solange, bis im Thread das Flag gesetzt wird. Das geht natürlich auch mit statischen Variablen, aber die mag ich nicht und möchte es deshalb mittels Referenzen hinkriegen... (mit C wäre das kein Problem... 🙄 )



  • 1. Hast du das mit den Referenzen anscheinend immer noch nicht verstanden
    2. Ist dein Code sowieso Müll und
    3. Wurden bereits Lösungen genannt



  • Hi!

    "Für die Blinden und die Tauben noch ein allerletztes mal".
    Das!:

    this.flag = flag;
    

    ist eine KOPIE! Du übergibst die Variable als Referenz, diese kannst du verändern und dann ist die Variable mit der du die Funktion aufgerufen hast verändert. Wenn du aber das obige machst, dann übergibst du die Variable als Referenz und dann wird der Inhalt in eine Memebervariable kopiert! Du kannst Referenzen nicht speichern.
    Naja, Unsafe ginge neben einer Wrapperklasse wohl auch nocht, aber da du scheinbar nicht verstanden hast wie das alles funktioniert, solltest du es erstmal lassen.

    Code-Hacker



  • So, nun mal ganz ruhig!

    Die Sache mit den Referenzen habe ich schon verstanden (in bin von C über C++ nach C# gekommen, da gehören Referenzen zum Alltag). Was ich gesucht habe, war ein Weg, Referenzen zu speichern! Daß das in C# nicht oder nur mit Umwegen geht, das ist neu für mich, und deshalb habe ich das 2. Beispiel hier gepostet. Es sollte verdeutlichen, daß die erste Lösung für mein Problem nicht anwendbar ist und ich hatte gehofft, es gäbe einen anderen Weg.

    Und noch was:
    Es ist ein Unterschied, ob ein Code Müll oder zweckmäßig ist. Die paar Zeilen, die ich hier gepostet habe, zeigen bei weitem nicht das gesamte Projekt. Das einzige, was sie zeigen, ist die Stelle, an der ich ein Problem habe.

    Also, vielleicht sollten wir in Zukunft etwas sachlicher miteinander umgehen!

    😡 CS



  • Da ein integer ein value-Type ist legt dir deine Zuweisung an die Member-variable eine Kopie von num an. Um die Referenz zu speichern kannst du deinen Integer per Boxing zum reference-Type machen:

    private object num;
     public Class1(ref int num)
      {
         this.num = (object)num; 
      }
    

    Jetzt hast du eine Referenz auf deine Variable. Allerdings musst du die bevor du sie wie einen normalen Integer benutzst erst wieder unboxen, also zurück zu int casten.

    Ich hoffe, das ist korrekt und war hilfreich 😉

    mfg, smasher1985



  • smasher1985@work schrieb:

    Da ein integer ein value-Type ist legt dir deine Zuweisung an die Member-variable eine Kopie von num an. Um die Referenz zu speichern kannst du deinen Integer per Boxing zum reference-Type machen:

    private object num;
     public Class1(ref int num)
      {
         this.num = (object)num; 
      }
    

    Jetzt hast du eine Referenz auf deine Variable. Allerdings musst du die bevor du sie wie einen normalen Integer benutzst erst wieder unboxen, also zurück zu int casten.

    Ich hoffe, das ist korrekt und war hilfreich 😉
    mfg, smasher1985

    Du vermischt hier call by ref und Referenzen (die man nur aus Marketing-Gründen so nennt. Im Grunde sind es Pointer). Was du hier machst macht keinen Sinn und wäre 1. genauso gut gegangen, wenn der Member num vom Typ int wäre und 2. wenn num nicht per call-by-ref übergeben worden wäre.



  • Wie der interpreter schon angedeutet hat, ist int ein value-Typ und um eine Referenz zu speichern brauchst du einen Referenz-Typ. Daher muss ein Wrapper benutzt werden und auf ref kann man dann verzichten. Zum Beispiel so:

    class IntWrapper
    {
    	private int _theValue;
    
    	public IntWrapper(int theValue)
    	{
            _theValue=theValue;
    	}
    
    	public static IntWrapper operator ++(IntWrapper i)
    	{
    		i._theValue++;
    		return i;
    	}
    
    	public static implicit operator int(IntWrapper i)
    	{
    		return i._theValue;
    	}
    }
    
    class Incrementor
    {
    	private IntWrapper _num;
    
    	public Incrementor(IntWrapper num)
    	{
    		_num=num;
    	}
    
    	public void Increment()
    	{
    		_num++;
    	}
    }
    
    class Class1
    {		
    	[STAThread]
    	static void Main(string[] args)
    	{
    		IntWrapper n = new IntWrapper(5);
    		Incrementor inc = new Incrementor(n);
    
    		inc.Increment();
            Console.WriteLine(n);	
    	}		
    }
    

Anmelden zum Antworten