Die Community zu .NET und Classic VB.
Menü

Tipp-Upload: VB.NET 0036: Arrays, Listen, Dictionaries - Initialisierung + Mehrdimensionalität

 von 

Über den Tipp  

Dieser Vorschlag soll VB.NET Tipp 2 ersetzen.

Dieser Tippvorschlag ist noch unbewertet.

Der Vorschlag ist in den folgenden Kategorien zu finden:

  • Sprachmerkmale

Dem Tippvorschlag wurden folgende Schlüsselwörter zugeordnet:
Array, List, Dictionary, initialisierung

Der Vorschlag wurde erstellt am: 05.09.2007 10:08.
Die letzte Aktualisierung erfolgte am 06.02.2009 20:57.

Zurück zur Übersicht

Beschreibung  

Hier werden drei grundlegende Klassen des Frameworks 2.0 eingehender betrachtet - es wird auf Möglichkeiten und Fallstricke hingewiesen

Als obsolete Auflistungstypen bitte nicht weiter verwenden:
System.Collections.ArrayList(Framework 1.1)
Microsoft.VisualBasic.Collection(VB6).
(Letztere nicht zu verwechseln mit der generischen System.Collections.ObjectModel.Collection(Of T) )

Da hier vor allem syntaktische Eigenarten beleuchtet werden, empfiehlt sich beim Testlauf, im Prozedurschritt (F10) vorzugehen, und die Ausgabe im AusgabeFenster zu beachten.

Schwierigkeitsgrad

Schwierigkeitsgrad 2

Verwendete API-Aufrufe:

Download:

Download des Beispielprojektes [12,84 KB]

' Dieser Source stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!
'
' Beachten Sie, das vom Designer generierter Code hier ausgeblendet wird.
' In den Zip-Dateien ist er jedoch zu finden.

' --------- Anfang Projektgruppe ArraysUndListen.sln ---------
' -------- Anfang Projektdatei ArraysUndListen.vbproj --------
' ----------------- Anfang Datei modMain.vb  -----------------
' Projekteinstellungen:
' Option Explicit On
' Option Strict On
' Imports Microsoft.VisualBasic.ControlChars
' Imports System
Imports System.Windows.Forms

Public Module modMain

    Public Sub Main()

        ' Array-Deklaration - beachte, daß der oberste gültige Index (UpperBound) um eines
        ' geringer ist als die Anzahl (Length) der Elemente.
        ' Dieses, weil auch die 0 ein gültiger Index ist
        Const Length0 As Integer = 10

        Dim Arr0(Length0 - 1) As Integer

        ' zwei Varianten, die Elemente zu enumerieren
        For I As Integer = 0 To Length0 - 1
            Arr0(I) = I
        Next

        For Each Value As Integer In Arr0
            WriteLine(Value)
        Next

        WriteLine()

        ' Bei der initialisierenden Deklaration entfällt die Angabe der Anzahl der Elemente - das
        ' "sieht" der Compiler selbst
        Dim Words As String() = New String() {"If", "Then", "Else"}

        ' Man kann auch knapper formulieren
        Dim SmartWords As String() = {"If", "Then", "Else"}

        ' noch einmal der Unterschied zwischen UpperBound und Länge eines Arrays:
        WriteLine("UpperBound: ", Words.GetUpperBound(0), ", Length: ", Words.Length, Lf)

        ' Arrays haben die schnellsten Zugriffszeiten, den geringsten Speicherverbrauch, und die
        ' Elemente sind typisiert.
        ' Außerdem bietet die Array-Klasse einen umfangreichen Satz schneller und nützlicher
        ' Methoden, (auf die ich hier nicht eingehe): IndexOf(), Find(), BinarySearch(), Sort(),
        ' Reverse(), CopyTo().

        ' ## Es können aber keine Elemente hinzugefügt oder entfernt werden. ##
        ' Redimensionieren erstellt ein neues Array, und kopiert ggfs. (Preserve) die Werte um.
        ' Das ist manchmal im Einzelfall sinnvoll (Optimierung auf Zugriffszeiten), aber v.a.
        ' Schleifen wie diese sind außerordentlich unperformant:
        For I As Integer = 0 To Length0 - 1
            ReDim Preserve Arr0(I)
            Arr0(I) = I
        Next

        ' stattdessen kann man die List(Of T) verwenden:
        Dim List0 As New List(Of Integer)

        For I As Integer = 0 To Length0 - 1
            List0.Add(I)
        Next

        ' Auf List(Of T) kann man dieselben beiden For-Schleifen anwenden wie auf T-Array

        ' List(Of T) kann man auch initialisieren - etwa mit einem Array
        Dim List1 As New List(Of String)(New String() {"If", "Then", "Else"})

        ' Leider kann man List(Of T) nicht mit einem ParamArray initialisieren
        ' Da schafft ein kleines Helfer-Funktiönchen etwas Abhilfe
        Dim List2 As List(Of String) = NewList("If", "Then", "Else")

        ' Kommen wir zur Mehrdimensionalität
        Call MultiDimensions()

    End Sub

    Public Function NewList(Of T)(ByVal ParamArray Items() As T) As List(Of T)

        Return New List(Of T)(Items)

    End Function

    Sub MultiDimensions()

        Dim Arr0(3, 1) As Integer

        ' Bei "echter Mehrdimensionalität" im Array reicht die Array.Length-Property nicht mehr
        ' aus, man muß den UpperBound der einzelnen Dimensionen ermitteln
        Dim YUbound As Integer = Arr0.GetUpperBound(0)
        Dim XUbound As Integer = Arr0.GetUpperBound(1)

        For Y As Integer = 0 To YUbound
            For X As Integer = 0 To XUbound

                ' (zur Erinnerung: UpperBound ist eins kleiner als die Länge des Arrays)
                Arr0(Y, X) = Y * (XUbound + 1) + X
            Next
        Next

        ' Kuriose ForEach-Iteration: Arr0 wird wie ein eindimensionales Array ausgelesen
        For Each Numb As Integer In Arr0
            WriteLine(Numb)
        Next

        ' Merkspruch: "Zeile zuerst, Spalte später"
        ' Es geht darum, daß es mathematisch gesehen egal ist, ob ein 2-dimensionales Array seine
        ' Elemente zunächst von oben nach unten durchgeht, und sich dann die nächste Spalte
        ' vornimmt, oder ob es von links nach rechts liest, und dann die nächste Zeile.
        ' Zu vermeiden ist nur, sein Array erst spaltenweise aufzubauen, und später dann
        ' zeilenweise auszulesen (außer, man beabsichtigt dieses explizit).
        ' Daher o.g. Konvention, der auch der Bildschirm-Aufbau folgt, oder etwa die alltägliche
        ' Lese-Richtung in der westlichen Kultur.
        ' Und bei derlei Arrays bedeuten die Indizees eben: "Zeile zuerst, Spalte später"

        ' Beweis: Initialisiere String(2, 1) ( = 3 Zeilen, 2 Spalten )
        Dim ArrDic As String(,) = {{"If", "Wenn"}, {"Then", "Dann"}, {"Else", "Andernfalls"}}

        ' Der Merkspruch gilt eben auch für den Aufbau verschachtelter Schleifen.
        For Y As Integer = 0 To 2           ' Zeile zuerst
            For X As Integer = 0 To 1       ' Spalte später
                Write(ArrDic(Y, X))
            Next

            WriteLine()
        Next

        WriteLine()

        ' Fallstricke lauern beim Umgang mit Grafik und mit Tabellen-Controls, da diese gegen o.g.
        ' Merkspruch verstoßen:
        Dim Pt As New System.Drawing.Point(X:=3, Y:=2)
        Dim DGV As New DataGridView : DGV.RowCount = 1 : DGV.ColumnCount = 1
        Dim C As DataGridViewCell = DGV(columnIndex:=0, rowIndex:=0)

        ' zur Vertiefung die Initialisierung eines 3-dimensionalen Arrays - beachten Sie den
        ' Einsatz der geschweiften Klammern
        Dim Wuerfel(,,) As Integer = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}

        ' ( Upperbound = 1, in allen 3 Dimensionen )
        For Z As Integer = 0 To 1
            For Y As Integer = 0 To 1
                For X As Integer = 0 To 1
                    Write(Wuerfel(Z, Y, X))
                Next

                WriteLine()
            Next

            WriteLine()
        Next

        WriteLine()

        ' "unechte Mehrdimensionalität" - Array von Arrays
        ' Angenommen, Sie brauchen ein Array, daß in Zeile Eins drei Einträge enthält, in Zeile
        ' zwei hingegen vier?
        ' Verwenden Sie ein Array von Arrays:
        Dim KeyWords As String()() = New String()() { New String() {"If", "Else", "End " & _
            "If"}, New String() {"Try", "Catch", "Finally", "End Try"}, New String() { _
            "Do", "Loop"}, New String() {"For", "Next"}, New String() {"Imports"}}

        For Y As Integer = 0 To KeyWords.Length - 1
            For X As Integer = 0 To KeyWords(Y).Length - 1

                ' Beim Zugriff hat jeder Index seine eigene Klammer, im Gegensatz zur "echten"
                ' Mehrdimensionalität
                Write(KeyWords(Y)(X))
            Next

            WriteLine()
        Next

        WriteLine()

        ' ForEach mal wieder eleganter:
        For Each Line As String() In KeyWords
            For Each Word As String In Line
                Write(Word)
            Next

            WriteLine()
        Next

        WriteLine()

        ' "unechte" Mehrdimensionalität mit List(Of T):
        Dim KeyWordList As List(Of List(Of String)) = NewList(NewList("If", "Else", "End " & _
            "If"), NewList("Try", "Catch", "Finally", "End Try"), NewList("Do", "Loop"), _
            NewList( "For", "Next"), NewList("Imports"))

        ' spaßeshalber mal ohne NewList()-Funktion (alle Listen mit Arrays initialisieren):
        KeyWordList = New List(Of List(Of String))(New List(Of String)() { New List(Of _
            String)(New String() {"If", "Else", "End If"}), New List(Of String)(New String() _
            {"Try", "Catch", "Finally", "End Try"}), New List(Of String)(New String() { _
            "Do", "Loop"}), New List(Of String)(New String() {"For", "Next"}), New List(Of _
            String)(New String() {"Imports"})})

        ' So eine Initialisierung ist nun wirklich nicht mehr sehr leserlich

        ' Dafür kann man aber sowohl Worte als auch ganze Zeilen nachträglich einfügen oder
        ' entfernen:
        KeyWordList(0).Insert(1, "Then")                   ' einer Gruppe ein Element zufügen
        KeyWordList.Insert(2, NewList("While", "Wend"))    ' eine Gruppe zufügen
        KeyWordList.RemoveAt(KeyWordList.Count - 1)        ' letzte Gruppe entfernen

        ' Der Zugriff ist identisch mit dem Zugriff bei Array-Arrays
        For Y As Integer = 0 To KeyWordList.Count - 1
            For X As Integer = 0 To KeyWordList(Y).Count - 1
                Write(KeyWordList(Y)(X))
            Next

            WriteLine()
        Next

        WriteLine()

        Call Dictionaries()

    End Sub

    Sub Dictionaries()

        ' Während Arrays und Listen einen numerisch indizierten Zugriff gewähren, bietet das
        ' Dictionary einen Zugriff über Schlüssel-**Objekte**
        ' Den Datentyp von Schlüssel und Wert kann man per generischem Parameter festlegen; hier
        ' ein einfaches Beispiel für Strings:
        Dim Dic As New Dictionary(Of String, String)

        With Dic
            .Add("If", "Wenn")
            .Add("Then", "Dann")
            .Add("Else", "Andernfalls")
        End With

        WriteLine("Dic(""If"") = ", Dic("If"))

        ' Eine manchmal(!) praktische Kuriosität beim Schreibzugriff: Existiert der Schlüssel noch
        ' gar nicht, so wird er immanent angelegt.
        Dic("End If") = "Ende Wenn"

        ' Beim Lese-Zugriff auf einen nicht vorhandenen Schlüssel erfolgt natürlich eine
        ' KeyNotFoundException
        Dim Response As String = Dic("Try")

        ' Dictionaries sind ebenfalls enorm schnell im Zugriff.
        ' Intern werden die Werte nach dem sog. Hashing-Verfahren "eingeräumt", was einen
        ' direkten Abruf ohne Such-Algorithmus ermöglicht

        ' Enumerieren kann man ein Dictionary auch, sogar in mehrfacher Hinsicht:
        For Each Entry As KeyValuePair(Of String, String) In Dic
            WriteLine(Entry.Key, " = ", Entry.Value)
        Next

        ' oder
        For Each Key As String In Dic.Keys
            WriteLine(Key)
        Next

        ' oder
        For Each Value As String In Dic.Values
            WriteLine(Value)
        Next

        ' anders als bei Listen haben wir hier aber **keinen numerischen Index**
        ' Dim P As KeyValuePair(Of String, String) = Dic(2) '<- geht nicht

        ' Beachten Sie, daß die .Keys() und .Values()-Property jeweils ein **Export** des
        ' Dictionaries ist.
        ' D.h., bei jedem Abruf wird intern eine Collection erstellt und befüllt, also das gesamte
        ' Dictionary durchlaufen.
        ' folgender Code ist also 3 mal performanter (an Geschwindigkeit *und* Speicherplatz) als
        ' der darauf folgende:
        Dim Values As Dictionary(Of String, String).ValueCollection = Dic.Values

        For I As Integer = 0 To 2
            For Each Val As String In Values

                ' machwas
            Next
        Next

        ' unperformant
        For I As Integer = 0 To 2
            For Each Val As String In Dic.Values

                ' machwas
            Next
        Next

    End Sub

End Module

''' <summary>zwei kleine Helferlein zur vereinfachten Ausgabe</summary>
Public Module modHelpers

    Public Sub WriteLine(ByVal ParamArray Args() As Object)

        Console.WriteLine(String.Concat(Args))

    End Sub

    Public Sub Write(ByVal Arg As Object)

        Console.Write(String.Concat(Arg, " "))

    End Sub

End Module

' ------------------ Ende Datei modMain.vb  ------------------
' --------- Ende Projektdatei ArraysUndListen.vbproj ---------
' ---------- Ende Projektgruppe ArraysUndListen.sln ----------

	

Diskussion  

Diese Funktion ermöglicht es, Fragen, die die Veröffentlichung des Tipps betreffen, zu klären, oder Anregungen und Verbesserungsvorschläge einzubringen. Nach der Veröffentlichung des Tipps werden diese Beiträge nicht weiter verlinkt. Allgemeine Fragen zum Inhalt sollten daher hier nicht geklärt werden.
Folgende Diskussionen existieren bereits

Um eine Diskussion eröffnen zu können, müssen sie angemeldet sein.