Structure und Instanzen

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von o815michi.

    Structure und Instanzen

    Hallo,

    sehr oft macht mir die Fehlermeldung: "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt." einen Strich durch meinen Code.

    Woran liegt es in meinen konkreten Beispiel.


    VB.NET-Quellcode

    1. Public Structure Grunddaten_neu
    2. Public Neu_Zeichen As String
    3. Public Ordner_Liste As ArrayList
    4. End Structure
    5. Public GDat As New Grunddaten_neu
    6. Public Sub setze_Grundwerte()
    7. Dim Ordner1 As String = "A, B, C"
    8. Dim Ordner2() As String
    9. Ordner2 = Ordner1.Split(",")
    10. GDat.Ordner_Liste.Addrange(Ordner2)
    11. End Sub


    Meiner Meinung nach, ist doch Gdat eine Instanze von Grunddaten_Neu, warum versteht das VB nicht?

    Ich habe dieses Vorgehensweise gewählt, weil ich aus Verschiedenen Klassen Werte in die Gdat-Struktur Speichern möchte, und diese dann gemeinsam Speichern möchte.
    Die Konstuktion mit Arraylist habe ich vor kurzen erst geänder, weil bei einem einfachen Stringarray es Probleme mit dem anfügen neuer "Ordner" gibt.

    Hat jemand Vorschläge für mich wie ich das Umbauen kann?

    Grüße
    o815michi

    Edit by ~blaze~:
    *VB-Tags eingefügt*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    Hi
    Innerhalb deiner Struktur existiert ja eine ArrayList (Ordner_Liste). Diese benötigt ebenfalls eine Instanz, um verwendet zu werden. Strukturen lassen das übrigens im parameterlosen Konstruktor nicht zu, daher würde ich auf eine Klasse ausweichen.

    Setze den Code bitte zukünftig in VB-Tags.

    Gruß
    ~blaze~
    Hallo,

    genau das wollte ich eigentlich vermeiden. Das macht mir ja nicht weniger Arbeit sondern wesentlich mehr. Nur um so ein paar Daten ordentlich speichern zu können.

    Danke, für die schnelle Antwort. Der nächste "NullReferenceException" ist sicherlich nicht weit.

    Was ich mich allerdings frage, ist, warum man dann Arraylists überhaut in einer Structure definieren kann, wenn sie dann nicht zu benutzen gehen. (Das Studio meldet ja sogar unbenutzte Variablen als Warnungen, warum sowas nicht.)

    Grüße
    o815michi
    Wieso sollte eine Klasse mehr Arbeit machen?
    Wenn du eine Arraylist deklarierst, dann mußt du vor dem Füllen auch eine Insatnz mit new Arraylist erzeugen. Das geht in einer Klasse problemlos mit public Ordnerlist as new Arraylist. (Oder auch Shared, wenns klassengebunden sein soll).
    Diese Klasse kann sogar als Shared Sub deine Speicherroutine enthalten. Die rufst du dann mit GDat.Speichern() auf und feddich.
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    Die nicht instanziierten Variablen werden nur gemeldet, wenn sie innerhalb einer Methode keinen Wert zugewiesen bekommen. Du kannst die ArrayList natürlich schon verwenden, nur musst du ihr halt außerhalb einen Wert zuweisen:

    VB.NET-Quellcode

    1. Dim Instance As New Grunddaten_neu
    2. Instance.Ordner_Liste = new ArrayList()


    Gruß
    ~blaze~
    Hallo,

    Wieso sollte eine Klasse mehr Arbeit machen?


    Nehmen wir mal nan ein ich Vergleiche eine Structure mit sagen wir mal 100 Variablen mit einer Klasse, die 100 Eigenschaften besitzt.

    Die Variablen schreibe ich recht schnell mit der zugehörigen Definitiom in die Stucture. Der Vollständigkei halber muss ich dann auch noch ein paar Methoden definieren die die Variablen bearbeiten.

    Bei der Klasse sieht das dann etwas anders aus. Als erstet muss ich die Klasse definieren, dann die ganzen Variablen und dann auch noch obendrauf die ganzen Propertys um auf die Variablen zugreifen zu können.
    Das wars aber noch nicht, für jede Methode die mir VB bereistellt brauche ich eine "übersetzter"-Methode in der Klasse.
    Will ich schnell die Count Eigenschaft einer Auflistung auslesen, kann ich das in der Strucktur recht problemlos. Aber in der Klasse muss ich erst eine Sub "Count auslesen" definiere, sonst geht es nicht.

    Vielleicht habe ich da auch etwas Grundsätzlich falsch verstanden, aber Klassen haben für mich so einen Anklang von viel Schreibarbeit mit wenig Inhalt und viel Speicherverbrauch. (Aus einer Variable mache ich ja 2 und mehr.)


    Grüße
    o815michi

    o815michi schrieb:

    Vielleicht habe ich da auch etwas Grundsätzlich falsch verstanden
    Ja, hast du.
    Du mußt nicht für jede Variable ne Property "obendrauf setzen". Die Property stellt dir lediglich die Methoden get und set zur Verfügung, in denen du beim setzen oder lesen einer variable reagieren kannst. z.B. könntest du im Set abfangen, dass der radius eines Kreises nicht 0 sein darf. Ist das nicht nötig, kannst du deine Variable einfach Public deklarieren und dann direkt mit Instanzname.variablename darauf zugreifen. Ist deine Liste als Public deklariert, kannst du ebenfalls mit Instanzname.Listenname.Listenmethode darauf zugreifen, also genauso einfach den Count erfahren, der dir solche Sorgen macht.
    Und noch etwas: Benötigst du nur 1 Instanz mit den 100.000 Variablen, kannst du alles als Shared deklarieren. Der Zugriff erfolgt dann mit Klassenname.Variablenname ohne das du vorher eine Instanz der Klasse erzeugen mußt.
    Der Unterschied zur Structur ist eigentlich vom Schreibaufwand her gleich.
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:

    o815michi schrieb:

    und dann auch noch obendrauf die ganzen Propertys um auf die Variablen zugreifen zu können.

    Wechsel halt auf VB 2010. Der unterstützt die vereinfachten Properties wie sie auch C# schon lange hat.

    Public Property Foo As String

    Kein Get, kein Set, keine interne Membervariable -> macht alles der Compiler automatisch! Die Membervariable heißt dann übrigens _Foo

    Liste.Count?

    Public Property Foo As List(Of String)

    MeineKlasse.Foo.Count ...

    Geht natürlich ohne "New" in der Klasse genauso in die Hose wie bei Struct ;)

    Übrigens haben Structures auch diverse Nachteile. zb "boxing"!
    knowdotnet.com/articles/boxedstructures.html

    Vatter schrieb:

    kannst du deine Variable einfach Public deklarieren und dann direkt mit Instanzname.variablename darauf zugreifen


    Ich weis, das das möglich ist. Aber laut meinen Informationen ist das keine gute Art zu programmieren. Für was brauche ich dann eigentlich die Klasse noch. Ich könnte das dann doch auch einfach in ein Modul machen. Die Diskussion ist mir aber etwas zu philosophisch.

    picoflop schrieb:

    Wechsel halt auf VB 2010.


    Nein danke, nicht schon wieder eine neue Programmierumgebung. Meine (unfertigen VB5 ) Programme haben es noch nicht alle auf VB2008 geschafft. Die die es geschaft haben sind grün vor Kommentaren "geht nicht" weil. ...


    VB.NET-Quellcode

    1. Public Structure Grunddaten_neu
    2. Public Pfad As String 'Einstellungspfad
    3. Public Shared Ordner_Liste As ArrayList 'String
    4. End Structure
    5. Public Sub Load2()
    6. If Not File.Exists(GDat.Pfad) Then Exit Sub
    7. FileOpen(1, GDat.Pfad, OpenMode.Binary, OpenAccess.Read)
    8. FileGet(1, GDat, 1)
    9. FileClose(1)
    10. Ordner_ausgeben()
    11. End Sub
    12. Public Sub Save2()
    13. FileOpen(1, GDat.Pfad, OpenMode.Binary, OpenAccess.Write)
    14. FilePut(1, GDat, 1)
    15. FileClose(1)
    16. End Sub
    17. Private Sub setze_Grundwerte()
    18. Grunddaten_neu.Ordner_Liste = New ArrayList()
    19. Dim Ordner1 As String = "A,B,C"
    20. 'Grunddaten
    21. 'testmodus
    22. GDat.Pfad = Environment.GetFolderPath(Environment.SpecialFolder.Personal) & "eigene\sonstiges\Programme\Datsort\Einstellungen.ini"
    23. 'Einstellungen
    24. Grunddaten_neu.Ordner_Liste.AddRange(Ordner1.Split(","))
    25. end sub


    Ich setze erst die Grundwerte, dann Speichere ich, oder Lade nach Bedarf (Wenn Datei vorhanden ist Lade ich logischerweise.)
    Warum pack Fileput den Inhalt der Arraylist nicht in die Datei? Die anderen Variablen sind alle vorhanden.


    Grüße
    o815michi
    Du musst das dann so gestalten:

    VB.NET-Quellcode

    1. Public Structure Grunddaten_neu
    2. Public Pfad As String 'Einstellungspfad
    3. Public Ordner_Liste As ArrayList 'String
    4. End Structure
    5. Private Sub setze_Grundwerte()
    6. Dim Ordner1 As String = "A,B,C"
    7. Dim gnInstance As New Grunddaten_neu()
    8. gnInstance.Ordner_Liste = New ArrayList()
    9. 'Grunddaten
    10. 'testmodus
    11. GDat.Pfad = Environment.GetFolderPath(Environment.SpecialFolder.Personal) & "eigene\sonstiges\Programme\Datsort\Einstellungen.ini"
    12. 'Einstellungen
    13. gnInstance.Ordner_Liste.AddRange(Ordner1.Split(","c))
    14. end sub


    Hab' neben der Verarbeitung der Struktur noch ein paar kleine Änderungen vorgenommen. Eventuell solltest du auch bei Environment.GetFolderPath eine Verknüpfung der Pfade mit IO.Path.Combine vornehmen. Da das aber eine ganze Verkettung ist mit den Ordnern (durch das \-Zeichen) und das ggf. auf anderen Systemen zu Problemen führt, empfehle ich die Verwendung folgendes Codes: [VB.NET] Mehrere Pfadteile verknüpfen

    Du solltest statt FilePut etc. die IO.StreamWriter- und IO.StreamReader-Klassen verwenden.

    Edit: Sorry, hab zu schnell auf Absenden geklickt.

    Gruß
    ~blaze~
    Hallo,

    ich habe mir einige Gedanken über den Code gemacht, und bin zu dem Schluss gekommen, das dieses Problem nun gelöst ist.

    Meine Lösung beinhaltet keine Arraylist mehr (die angeblich viel kompfortabler Daten speichert) sondern ein ganz normales Array was in allen meinen wichtigen Belangen besser funktioniert.

    Hier die Klasse zum Erzeugen, Laden, Speichern und Grundwerte setzen
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Load_Save
    2. Public Structure Grunddaten_class
    3. Public Pfad As String 'Einstellungspfad
    4. '...
    5. Public Ordner_Liste() As String
    6. '...
    7. End Structure
    8. Public Gdat As New Grunddaten_class
    9. Public Sub Save()
    10. FileOpen(1, Pfad, OpenMode.Binary)
    11. FilePut(1, Gdat)
    12. FileClose(1)
    13. End Sub
    14. Public Sub Load()
    15. FileOpen(1, Pfad, OpenMode.Binary)
    16. FileGet(1, Gdat)
    17. FileClose(1)
    18. End Sub
    19. Private Sub Setze_Grundwerte()
    20. Dim Ordner1 As String ="A.B,C"
    21. Dim L1() As String
    22. L1 = Ordner1.Split(",")
    23. For A = 0 To L1.GetUpperBound(0)
    24. Gdat.Ordner_Liste(A) = L1(A)
    25. Next
    26. end class


    Die Klasse Einstellungen, wo die Ordnerliste gespeichert wird.
    (In die Listbox wird die Liste beim Start eingelesen und beim klicken auf Speichern so abgespeichert.
    In der Listbox kann man dann Löschen, Ändern und hinzufügen)
    LB1 = Listbox1 / LS = Load_Save instance
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public LS As New Load_Save
    2. Private Sub CB1_Click ...
    3. 'Einstellungen speichern
    4. Dim ICO, A As Integer
    5. ICO = LB1.Items.Count - 1
    6. ReDim LS.Gdat.Ordner_Liste(ICO)
    7. A = 0
    8. For Each Item As String In LB1.Items
    9. LS.Gdat.Ordner_Liste(A) = Item
    10. A += 1
    11. Next
    12. LS.Save()
    13. Me.Close()
    14. End Sub



    Der Array hat den großen Vorteil das sowohl Fileput als auch FileGet die Strucktur als ganzes behandeln und alles mit allen Elementen machen.
    Ich muss daher nicht wie es wahrscheinlich bei der Arraylist ist jedes Element einzeln ansprechen. Dadurch erspare ich mir recht viel Code.
    (Grunddaten_class enthält ja inzwischen 17 Mitglieder davon 5 Arrays.
    Ich weis, das mein Code an einigen Stellen sehr ausführlich ist. Das ist so gewollt wegen der vielen zwischenzeitlichen Änderungen.
    Wenn Deklarationen vermisst werden, möchte ich darauf hinweisen, das ich sie nur vergessen habe sie zu kopieren. Sie sind auf 10 verschiedene Klassen/Module verteilt.)

    Grüße
    o815michi