Entwickler-Ecke

C# - Die Sprache - ref this


duckhunter - Mi 26.09.07 17:34
Titel: ref this
Hi Leute,

ich habe vor von VB auf C# umzusteigen. Allerdings habe ich schon ein Problem.

Ich habe eine Root-Klasse. In dieser Root-Klasse befinden sich mehrere "Unterklassen". Ich mochte aber von diesen Unterklassen auf die Eigenschaften der Root-Klasse zugreifen und diese auch verändern können. In VB ging das so.


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
Module Module1

    Sub Main()
        Dim _Root As New Root()
        Console.ReadKey()
    End Sub

    Private Class Root

        Dim _i As Integer
        Dim _Unterklasse As Unterklasse

        Public Sub New()
            _i = 5
            Console.WriteLine(_i.ToString())
            _Unterklasse = New Unterklasse(Me)
            Console.WriteLine(_i.ToString())
        End Sub

        Private Class Unterklasse

            Public Sub New(ByRef RootKlasse As Root)
                RootKlasse._i = 10
            End Sub

        End Class

    End Class

End Module


Hier klappt alles wunderbar. Die Variable _i hat zuerst den Wert 5, dann wird sie über die andere Klasse geändert und hat den Wert 10. Nun das gleiche in C#.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Root _Root = new Root();
            Console.ReadKey();
        }

        private class Root
        {
            int _i;
            Unterklasse _Unterklasse;

            public Root()
            {
                _i = 5;
                Console.WriteLine(_i.ToString());
                _Unterklasse = new Unterklasse(ref this);
                Console.WriteLine(_i.ToString());
            }

            private class Unterklasse
            {
                public Unterklasse(ref Root RootKlasse)
                {
                    RootKlasse._i = 10;
                }
            }
        }
    }
}


Hier kommt dann der Fehler:
"<this>" kann nicht als ref- oder out-Argument übergeben werden, da das Element schreibgeschützt ist.


Kann ich das irgendwie umgehen oder gibt es vielleicht sogar eine ellegantere Lösung für das Problem?

mfg und vielen Dank im Voraus
duckhunter


Kha - Mi 26.09.07 19:24

VB kompiliert das? Lol[1].
Eine Übergabe by reference ist hier jedenfalls unnötig, da du der Variablen selbst nichts zuweist, nur eine Eigenschaft änderst. Den ref-Modifier solltest du also einfach so entfernen können.
Noch ein paar Tipps:


[1]Nein, mehr fällt mir dazu wirklich nicht ein.


duckhunter - Mi 26.09.07 19:46

Hmm das versteh ich jetzt nicht ganz, wie sollte ich dann auf die Root-Klasse zugreifen, wenn in dieser was geändert werden muss?

danke für die Hilfe!!

mfg


Kha - Mi 26.09.07 19:50

Wenn meine Erklärung nix taugt, klau ich eben eine aus dem SDK :-B :
Passing Reference-Type Parameters (C# Programming Guide) hat folgendes geschrieben:
A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a reference-type parameter by value, it is possible to change the data pointed to by the reference, such as the value of a class member. However, you cannot change the value of the reference itself; that is, you cannot use the same reference to allocate memory for a new class and have it persist outside the block. To do that, pass the parameter using the ref or out keyword.


duckhunter - Mi 26.09.07 20:15

Hmmm ... jetzt hab ich alles verstanden *gggg*.

Sorry steh im Moment voll auf der Leitung, kannst du das vllt in einen Source Code oder als Beispiel anführen?

Danke ;)

mfg


Kha - Mi 26.09.07 20:54

Noch einmal: Entferne einfach die zwei ref und dein Programm wird funktionieren.


duckhunter - Mi 26.09.07 21:04

Ahh sehr gut danke.

Aber warum funktioniert es in diesem Fall?

Wenn ich z.B. folgenden Programmcode habe:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
using System;
using System.Collections.Generic;
using System.Text;


namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Root _Root = new Root();
            Console.ReadKey();
        }


        private class Root
        {
            int _i;
            Unterklasse _Unterklasse;


            public Root()
            {
                _i = 5;
                Console.WriteLine(_i.ToString());
                _Unterklasse = new Unterklasse(_i);
                Console.WriteLine(_i.ToString());
            }


            private class Unterklasse
            {
                public Unterklasse(int i)
                {
                    i = 10;
                }
            }
        }
    }
}


Wenn ich das so programmiere, dann wird i natürlich nicht 10, außer ich übergebe es so:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
            public Root()
            {
                _i = 5;
                Console.WriteLine(_i.ToString());
                _Unterklasse = new Unterklasse(ref _i);
                Console.WriteLine(_i.ToString());
            }


            private class Unterklasse
            {
                public Unterklasse(ref int i)
                {
                    i = 10;
                }
            }


Warum wird nun die Variable i in der Klasse (ohne der ref-Übergabe) geändert und warum wird i nicht geändert, wenn ich nur die Variable (wie im Codeblock 1) übergebe. Wenn ich mit i mit ref Übergebe (Codeblock 2) funktioniert es logischerweise.

mfg

Edit:
Sry war mein Fehler, jetzt ist alles klar.... Ich habe hier ja nur ein schnelles Beispiel angegeben, was ich in Wirklichkeit für was komplexeres benötige... Naja egal auf jeden Fall jetzt klappt alles, danke nochmal Khabarakh!