none
String ByRef vorhalten RRS feed

  • Frage

  • Hallo alle zusammen.

    Bei der Instanziierung möchte ich an eine Struktur (TStruc) den Verweis auf eine Zeichenfolgen-Eigenschaft (tProp) übergeben und in der Struktur vorhalten.

    Wenn ich die Zeichenfolgen-Eigenschaft der Struktur (TStruc.Value) setze, soll diese Zeichenfolge nicht nur in der Struktur gehalten sondern auch als Wert der externen Zeichenfolgen-Eigenschaft (tProp) gespeichert werden, deren Verweis ich bei der Instanziierung übergeben hatte.

    Ich hoffe, ich habe mich einigermaßen verständlich ausgedrückt.

    Dazu hatte ich mir folgenden Programmcode vorgestellt:

            Public Sub TSub()
                Dim tProp As String = "irgendetwas"
                Dim tStr As TStruc = New TStruc(tProp)
                tStr.Value = "was ganz anderes"
                Console.WriteLine("Strukturwert     : {0}", tStr.Value)
                Console.WriteLine("Eigenschaftswert : {0}", tProp)
                Console.ReadLine()
            End Sub
    
            Public Structure TStruc
                Private Property _pValue As String
                Private Property _value As String
                Public Property Value As String
                    Get
                        Return _value
                    End Get
                    Set(nValue As String)
                        _value = nValue
                        _pValue = nValue
                    End Set
                End Property
    
                Public Sub New(ByRef pValue As String)
                    _pValue = pValue
                End Sub
            End Structure

    Als Ausgabe in der Routine TSub hatte ich mir dann folgendes erhofft:

    Strukturwert     : was ganz anderes
    Eigenschaftswert : was ganz anderes

    Statt dessen bekomme ich:

    Strukturwert     : was ganz anderes
    Eigenschaftswert : irgendetwas

    Ich halte also nicht den Verweis auf die Eigenschaft vor.

    Allerdings habe ich auch schon vielerlei versucht. Entweder bringt es nichts oder geht nicht bei "Option Strict On".

    Sieht jemand meinen Denkfehler oder kann mir sonst einen verwertbaren Tipp geben?

    Vielen Dank.


    WM

    Dienstag, 20. Juni 2017 13:01

Antworten

  • .

    Dein Vorschlag funktioniert ... aber nur einmal. Jedes Mal, wenn ich tStr.Value neu zuweise, müsste ich erneut tStr.SetRef(tProp) aufrufen. Dabei wäre mir schon das erste Mal zu viel.



    Das liegt daran, das Du ja die Referenz immer wieder überschreibst.

    In VB.Net wird bei Strings bei der Zuweisung von Konstanten immer ein neuer Verweis gesetzt.

    str1 = "Text1"

    str1 = "Neuer Text"

    Dabei ist es nicht so, dass str1 eine immer gleiche Referenz ist die nur den Inhalt wechselt.

    Es ist tatsächlich so, das str1 zunächst auf die Konstante "Text1" verweist und dann auf "Neuer Text"

    Ein Lösung Deines Problems könntest DU aber mit dem Typ Stringbuilder erreichen. Der Stringbuilder legt zunächst eine Instanz (Referenz) an, und es kann später auch nur der Inhalt verändert werden.

    Nachfolgend Dein Beispiel mit Stringbuilder. Zur Verdeutlichung wird der Inhalt der Referenzvariable zweimal verändert.

    Hier das Beispiel:

        Public Sub TSub()
            Dim tProp As StringBuilder = New StringBuilder("irgendetwas")
            Dim tStr As TStruc = New TStruc(tProp)
            'tStr.SetRef(tProp)
            tStr.Value = "was ganz anderes"
            Console.WriteLine("Strukturwert     : {0}", tStr.Value)
            Console.WriteLine("Eigenschaftswert : {0}", tProp.ToString())
            tStr.Value = "noch was ganz anderes"
            Console.WriteLine("Strukturwert     : {0}", tStr.Value)
            Console.WriteLine("Eigenschaftswert : {0}", tProp.ToString())
            Console.ReadLine()
        End Sub
    
        Public Structure TStruc
            Private rValue As StringBuilder
            Private _pValue As String
            Private Property _value As String
            Public Property Value As String
                Get
                    Return _value
                End Get
                Set(ByVal nValue As String)
                    _value = nValue
                    _pValue = nValue
                    rValue.Clear()
                    rValue.Append(nValue)
                End Set
            End Property
    
            Public Sub New(ByRef pValue As StringBuilder)
                _value = pValue.ToString()
                _pValue = pValue.ToString()
                rValue = pValue
            End Sub
        End Structure

    _pvalue wird hier nicht mehr benötigt ich habe die Variable aber nicht entfernt.


    Grüße

    Roland


    Dienstag, 20. Juni 2017 17:50

Alle Antworten

  • Hallo WM,

    ich bin mir nicht sicher was Du genau vor hast. Ist es eine konkrete Aufgabenstellung, oder willst Du eine Übungsaufgabe zum Zeigen des Unterschiedes zwischen Referenz- und Werttypen erstellen.

    Um Dein gewünschtes Ziel zu erreichen könntest Du so vorgehen:

        Public Sub TSub()
            Dim tProp As String = "irgendetwas"
            Dim tStr As TStruc = New TStruc(tProp)
            tStr.Value = "was ganz anderes"
            tStr.SetRef(tProp)
            Console.WriteLine("Strukturwert     : {0}", tStr.Value)
            Console.WriteLine("Eigenschaftswert : {0}", tProp)
            Console.ReadLine()
        End Sub
    
        Public Structure TStruc
            Private _pValue As String
            Private Property _value As String
            Public Sub SetRef(ByRef RefVar As String)
                RefVar = _pValue
            End Sub
    
            Public Property Value As String
                Get
                    Return _value
                End Get
                Set(ByVal nValue As String)
                    _value = nValue
                    _pValue = _value
                End Set
            End Property
    
            Public Sub New(ByRef pValue As String)
                _value = pValue
            End Sub
        End Structure

    Dabei habe ich Deine Refernzvariable tProp mit einer Methode übergeben.

    Grüße

    Roland 



    Dienstag, 20. Juni 2017 14:50
  • Hallo Roland,

    nein, es ist keine Übungsaufgabe. Es ist lediglich ein zusammengestutzer und verallgemeinerter Plan aus meiner Praxis.

    Dein Vorschlag funktioniert ... aber nur einmal. Jedes Mal, wenn ich tStr.Value neu zuweise, müsste ich erneut tStr.SetRef(tProp) aufrufen. Dabei wäre mir schon das erste Mal zu viel.

    Ich möchte mit der Konstruktion erreichen, dass ich mit der Struktur arbeite, aber auf die Werte auch ohne Struktur zugreifen kann. Das bedeutet, dass die für die Struktur externe Eigenschaft immer automatisch, ohne tStr.SetRef(), zugewiesen sein müsste.

    Die Struktur beinhaltet eine ganze Menge zusätzlicher Eigenschaften, deren Verwaltung klappt. In der normalen Praxis kommt es aber immer nur auf den Wert an, auf den ich bspw. zugreifen möchte mit strBsp = class.Property und nicht mit strBsp = class.structure.Value. Mir wäre das noch ziemlich egal. Die Anwender kennen aber den Property-Name und werden sich schwer tun, mit .Value zu arbeiten.

    Dein Vorschlag zeigt aber, dass es irgendwie gehen wird. Ich bin optimistisch und werde weiter daran arbeiten. Inzwischen bin ich dankbar für jeden weiteren Vorschlag.

    Vielen Dank.


    WM

    Dienstag, 20. Juni 2017 15:49
  • Hi WerMil,
    Dein Ansinnen ist in VB.NET nicht realisierbar, da VB.NET keine Nutzung von Pointern für Felder unterstützt. Lediglich Pointer auf Methoden können mit AddressOf Variablen vom Type Delegate zugewiesen werden.

    Du übergibst zwar einen Pointer (Referenz) dem Konstruktur. Mit der nachfolgenden Zuweisung wird der Inhalt geholt. Obwohl String vom Referenztyp ist, wird mit der Zuweisung aber der Inhalt analog einer Variablen vom Wertetyp übertragen. Und damit wird der Wert am ursprüngliche Ort vom Speicherort in der Struktur entkoppelt.

    Um Dein Ansinnen zu realisieren, müsstest Du Dir im Konstruktor den Pointer auf die übergebene Variable merken und bei späteren Aufruf der Value-Eigenschaften diesen Pointer für Wertezuweisung nutzen. Und das lässt die CLR aus Sicherheitsgründen nicht zu.

    Die einzige "Krücke", die vielleicht möglich wäre, ist die Nutzung einer Overlay-Struktur. Ob es da einen Weg gibt, habe ich nicht probiert, da ich die Nutzung von Methoden in Strukturen pervers finde. Eine Implementierung in Klassen scheint mir besser angebracht. Strukturen sind zwar schneller als Objekte, da sie im Stack gehalten werden. Intensive Nutzung kann aber schnell zum Überlauf des Stacks führen.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 20. Juni 2017 17:15
  • .

    Dein Vorschlag funktioniert ... aber nur einmal. Jedes Mal, wenn ich tStr.Value neu zuweise, müsste ich erneut tStr.SetRef(tProp) aufrufen. Dabei wäre mir schon das erste Mal zu viel.



    Das liegt daran, das Du ja die Referenz immer wieder überschreibst.

    In VB.Net wird bei Strings bei der Zuweisung von Konstanten immer ein neuer Verweis gesetzt.

    str1 = "Text1"

    str1 = "Neuer Text"

    Dabei ist es nicht so, dass str1 eine immer gleiche Referenz ist die nur den Inhalt wechselt.

    Es ist tatsächlich so, das str1 zunächst auf die Konstante "Text1" verweist und dann auf "Neuer Text"

    Ein Lösung Deines Problems könntest DU aber mit dem Typ Stringbuilder erreichen. Der Stringbuilder legt zunächst eine Instanz (Referenz) an, und es kann später auch nur der Inhalt verändert werden.

    Nachfolgend Dein Beispiel mit Stringbuilder. Zur Verdeutlichung wird der Inhalt der Referenzvariable zweimal verändert.

    Hier das Beispiel:

        Public Sub TSub()
            Dim tProp As StringBuilder = New StringBuilder("irgendetwas")
            Dim tStr As TStruc = New TStruc(tProp)
            'tStr.SetRef(tProp)
            tStr.Value = "was ganz anderes"
            Console.WriteLine("Strukturwert     : {0}", tStr.Value)
            Console.WriteLine("Eigenschaftswert : {0}", tProp.ToString())
            tStr.Value = "noch was ganz anderes"
            Console.WriteLine("Strukturwert     : {0}", tStr.Value)
            Console.WriteLine("Eigenschaftswert : {0}", tProp.ToString())
            Console.ReadLine()
        End Sub
    
        Public Structure TStruc
            Private rValue As StringBuilder
            Private _pValue As String
            Private Property _value As String
            Public Property Value As String
                Get
                    Return _value
                End Get
                Set(ByVal nValue As String)
                    _value = nValue
                    _pValue = nValue
                    rValue.Clear()
                    rValue.Append(nValue)
                End Set
            End Property
    
            Public Sub New(ByRef pValue As StringBuilder)
                _value = pValue.ToString()
                _pValue = pValue.ToString()
                rValue = pValue
            End Sub
        End Structure

    _pvalue wird hier nicht mehr benötigt ich habe die Variable aber nicht entfernt.


    Grüße

    Roland


    Dienstag, 20. Juni 2017 17:50
  • Guten Morgen Peter und Roland und herzlichen Dank.

    Zunächst Peter:

    Ich hatte es geahnt, dass es maximal mit Krücke gehen wird. Ich bin aber auch kein Krückenfan.

    Allerdings war mir so, als hätte ich das in C# schon einmal elegant lösen können.

    Entweder bilde ich mir das nur ein oder VB ist eben doch nicht mit C# auf eine Stufe zu stellen...

    Sodann Roland:

    Danke. Das ist eine gute Idee.

    Es ist zwar auch eine Krücke und mir ist mit Blick auf die Konsequenzen Laufzeitverhalten, Stackoverflowpotenzial und die Gesichter der Anwender auch nicht ganz wohl dabei.

    Aber aus jetziger Sicht ist es eine verwendbare Krücke, die ich auch anwenden und durchsetzen werde.

    Nochmals besten Dank.

    Gruß

    Werner


    WM


    • Bearbeitet WerMil Mittwoch, 21. Juni 2017 08:44
    • Als Antwort markiert WerMil Mittwoch, 21. Juni 2017 08:46
    • Tag als Antwort aufgehoben WerMil Mittwoch, 21. Juni 2017 12:25
    Mittwoch, 21. Juni 2017 08:32
  • Hallo WM,

    das mit der Krücke scheint nur so.

    Das ist die einzige und auch korrekte und empfohlen Methode wenn es darum geht mit Strings und Referenzen zu arbeiten.

    Wenn Dir der Type Stringbuilder nicht zusagt, ist es eine Kleinigkeit eine eigene Klasse zB. myString zu verwenden.

    Nachfolgend ein Beispiel mit der myString Klasse:

        Public Sub TSub()
            Dim tProp As myString = New myString("irgendewas")
            Dim tStr As TStruc = New TStruc(tProp)
            tStr.Value = "was ganz anderes"
            Console.WriteLine("Strukturwert     : {0}", tStr.Value)
            Console.WriteLine("Eigenschaftswert : {0}", tProp.Value)
            tStr.Value = "noch was ganz anderes"
            Console.WriteLine("Strukturwert     : {0}", tStr.Value)
            Console.WriteLine("Eigenschaftswert : {0}", tProp.Value)
            Console.ReadLine()
        End Sub
    
        Public Structure TStruc
            Private rValue As myString
            Private Property _value As String
            Public Property Value As String
                Get
                    Return _value
                End Get
                Set(ByVal nValue As String)
                    _value = nValue
                    rValue.Value = nValue
                End Set
            End Property
            Public Sub New(ByRef pValue As myString)
                _value = pValue.Value
                rValue = pValue
            End Sub
        End Structure
        Public Class myString
            Private _value As String
            Private newPropertyValue As String
            Public Property Value() As String
                Get
                    Return _value
                End Get
                Set(ByVal value As String)
                    _value = value
                End Set
            End Property
            Public Sub New(value As String)
                _value = value
            End Sub
        End Class
    

    Grüße

    Roland

    PS:Du hast wahrscheinlich aus versehen Deinen Kommentar auf meine Anwort als Antwort markiert, könntest Du das bitte noch korrigieren, damit bei einer Suche von anderen Mitgliedernauch  die Lösung auf die Frage gefunden wird ;-)

    Mittwoch, 21. Juni 2017 09:51
  • Danke Roland.

    Das mit der Krücke war auch nicht bezüglich der Korrektheit gemeint sondern viel mehr darauf bezogen, dass meine Anwender eben einen Typ String gewohnt waren und wohl weiterhin erwarten. Da hilft auch die eigene Klasse nichts.

    Aber dennoch vielen Dank für den Nachtrag.

    Die Antwort sollte ich aus versehen markiert und nun wohl auch wieder zurückgenommen haben.

    Viele Grüße

    Werner


    WM

    Mittwoch, 21. Juni 2017 12:29