Benutzer mit den meisten Antworten
Array in Strukturvariable

Frage
-
Hallo Experten,
auf Tip von Euch habe ich eine Strukturvariable (Fragen) definiert. Diese Struktur enthält die Variable Antworten, welche ein Array darstellt. Da die größe des Arrays innerhalb der Strukturdefinition nicht festgelegt werden kann (warum auch immer) muss diese später (denke ich erfolgen) im Code gemacht werden. Der folgende Code erzeugt entsprechen einen Fehler sobald ich der Variable Fragen(index).Antworten(index) ein Wert zuweise.
Public Structure Fragen Public Verwendet As Boolean Public Bereich As String Public SGrad As String Public Frage As String Public Antworten() As String Public RAntwort As Int16 End Structure Public Sub read() Dim i As Int16=1 Dim xFragen(35) as Fragen xFragen(i).Verwendet = False xFragen(i).Bereich = "X1" xFragen(i).SGrad = "X2" xFragen(i).Frage = "X3" xFragen(i).Antworten(0) = "Hier ist der Fehler" .... end Sub
Wo und wie kann ich das Array von ...Antworten auf z.B. 3 festlegen.
Vielen Dank mfg eem monarch
Antworten
-
Hallo,
da ändert sich (fast) gar nichts.
Ergänze den Code (bzw. ändere Testen):Public Sub Read() Read(Path.Combine(Application.StartupPath, "Fragen.dat")) End Sub Public Sub Read(ByVal fileName As String) If Not File.Exists(fileName) Then Return End If ' .NET 4 For Each eingabe In File.ReadLines(fileName) Dim felder = eingabe.Split("|"c) Dim frage = New Frage() With { .Bereich = felder(1), .SGrad = felder(2), .Frage = felder(3), .Antworten = New List(Of String) From {felder(4), felder(5), felder(6), felder(7)}, .RAntwort = Integer.Parse(felder(8)) } Me.Add(Frage) Next End Sub ' Fürs Testen... Friend Shared Sub Test() 'Dim alleFragen = Fragen.Create() Dim alleFragen = New Fragen() alleFragen.Read() For Each f In alleFragen Console.WriteLine("Frage: {0}, Antworten: {1}", f.Frage, f.Antworten.Count) For Each a In f.Antworten Console.WriteLine(" Antwort: " & a) Next Next End Sub
wobei ich einen andere Pfadangabe verwendet habe, mit dem Input:|X0|X1|Struktur oder Klasse|Struktur|Klasse|Keines von beiden||1 |X1|X2|Array oder Auflistung|Array|Auflistung|||1 |X2|X3|Frage ohne Antwort|1. Antwort|2. Antwort|3. Antwort|4. Antwort|5 |X2|X4|Frage ohne Antwort|||||0
Willst Du die Löcher (fehlende Antworten) loswerden, wirf
.Antworten = New List(Of String) From {felder(4), felder(5), felder(6), felder(7)},
oben aus dem Konstruktor raus und füge nur die nicht-leeren hinzu, z. B.
For Each antwort In {felder(4), felder(5), felder(6), felder(7)} If Not String.IsNullOrEmpty(antwort) Then frage.Antworten.Add(antwort) End If Next
Gruß Elmar
- Als Antwort markiert Monarch-Falter Donnerstag, 19. Januar 2012 16:42
Alle Antworten
-
Hallo,
soweit ich weiß, kannst Du innerhalb Deiner Structure auch eine Sub New() definieren. Hier kannst Du dann Dein Array initialisieren.
Ohne Gewähr. Ich kanns an meinem Handy nicht testen :-)
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
Hallo,
irgendwie kommt mir das bekannt vor: Structure Variable mit Array
was wohl im Weihnachtstrubel untergegangen ist...Schon dort gesagt: Verwende eine Klasse (Class).
Strukturen sind für leicht gewichtige (und oft kurzlebige) Objekte gedacht.
Und damit sie das sein können, erfolgt das Erzeugen direkt durch die CLR,
die alle Variablen mit dem Standardwert (0) vorbelegt.
Deswegen ist dort auch kein Standardkonstruktor möglich - der würde gar nicht verwendet.Das ist aber nur einer der Gründe warum man keine Struktur verwenden sollte.
Unabhängig von Struktur oder Klasse:
Antworten() As String
ist zunächst die Deklaration (Platzhalter) einer Array-Variablen, und es wird damit noch kein Array erzeugt.
Dies würde erst durch new geschehen, z. B.:Antworten = new String(2) {} ' Ein leeres Array für 3 Strings ' oder auch Antworten = { "1. Antwort", "2. Antwort", "3. Antwort" }
weitere Varianten: Gewusst wie: Initialisieren von Arrayvariablen in Visual BasicEin Nachteil von Arrays ist aber, dass sie in ihrer Größe fest dimensioniert sind.
Ändert sich die Größe im Nachhinein (hier: kommen Antworten hinzu oder fallen weg),
so muss ein neues Array erzeugt werden und die Inhalte übertragen werden.
(Die Redim Anweisung von Visual Basic tut auch nichts anderes.)Auch alle anderen Optionen, z. B. Verschieben oder Einfügen einer Antwort, sind bei Arrays
mit relativ mehr Aufwand verbunden.Deswegen hatte ich Dir schon damals als Alternative die List(T) empfohlen.
Dort ist werkelt im Hintergrund auch ein Array. Aber die Operationen fürs
Anfügen (Add), Einfügen (Insert), Löschen (Remove, RemoveAt) usw. sind
dort schon ausprogrammiert.Und was das Initialiseren in Read angeht, weisst Du ja seit gestern wie Du es
direkter hinbekommen kannst.Und machst Du aus den Antworten zudem eine Standard Eigenschaft,
so kannst Du sie (fast) genauso verwenden wie ein Array.Gruß Elmar
-
Servus Elmar,
nein ist nicht untergegangen , also das List(T) verwende ich , was ja auch von Vorteil ist. Wie ich aber folgende Anforderung in ein List(T) bekommen bzw. verwalten soll ist mir unklar.
1) Wie ich festgestellt habe ist eine Festlegung der Dimension innerhalb der Strukturdefinition (Public Structure Fragen ... end Structure) grundsätzlich nicht möglich.
2) Wenn ich ein Array z.B xFragen(35) as Fragen definiere, ist die Dimension von Antworten immer noch null. Diese muss über Redim erzeugt werden, wie jetzt festgestellt habe. Das hat Vorteil in meinen Fall da ich je xfragen(x) die Dimension für Antworten einzeln festlegen kann. z.B. redim xFragen(1).Antworten(4) und redim xfragen(3).Antworten(6).
3) Ich habe je nach Configuration(durch User) Controls erzeugt, welche im einer List(of T) zusammengefast sind. Über den Index (item) läst sich nun recht einfach eine Beziehung zu der Strukturvariable aufbauen.
Da die Wertinhalte der Struktur statisch ist und nur innerhalb einer Form gebraucht werden, (was ja auch nichts anderes als eine Klasse ist, soweit ich das verstanden habe), ist doch eine Variablenstruktur ein guter Weg oder ?
mfg eem monarch
P.S: der folgende Code von gestern habe ich so vor dir auch übernommen
Dim labelList As List(Of Label) Public Sub New() InitializeComponent() labelList = New List(Of Control) From { Me.Label1, Me.Label2 } End Sub
- Bearbeitet Monarch-Falter Donnerstag, 19. Januar 2012 10:55
-
So, ich nochmal.
Ich würde auch ein Klasse bevorzugen, aber ich dachte wenn Du schon nach einer Structure frägst....
hmmm und wie soll mir das helfen ????
'Visual Basic 2008 - .net 3.5 - Any CPU Public Structure Fragen Public Verwendet As Boolean Public Bereich As String Public SGrad As String Public Frage As String Public Antworten() As String Public RAntwort As Int16 Public Sub New(ByVal AnzahlDerAntworten As Integer) Antworten = New String (AnzahlDerAntworten - 1) {} End Sub End Structure
'Visual Basic 2008 - .net 3.5 - Any CPU Public Sub read() Dim i As Int16 = 1 Dim xFragen(35) As Fragen xFragen(i) = New Fragen(5) xFragen(i).Verwendet = False xFragen(i).Bereich = "X1" xFragen(i).SGrad = "X2" xFragen(i).Frage = "X3" xFragen(i).Antworten(0) = "Hier ist kein Fehler mehr" End Sub
übrigens: Arrays in VB.NET sind immer 0 basierend. Also Dein Array xFragen(35) geht von xFragen(0)...xFragen(35)
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/
- Bearbeitet Heslacher Donnerstag, 19. Januar 2012 16:14 Elmar beglückt
-
Hallo,
zu 1)
Das liegt am bereits beschriebenen Verhalten. Es wird bei Strukturen kein Konstruktur ausgeführt,
ergo kann auch kein Array erzeugt werden (das braucht wiederum ein new, wie ausgeführt).Und wie gesagt: Wenn Du keinen guten Grund hast eine Structure zu verwenden, ist Class die richtige Wahl.
Hier sprechen sogar konkrete Gründe dagegen:
Nur Klassen können für die Datenbindung verwendet werden (die braucht u. a. auch Eigenschaften,
deswegen werden unten ebensolche verwendet)
Aber auch andere Framework Komponenten, z. B. das Entity Framework für die Datenspeicherung erfordern eine Klasse.
Mit der Wahl als Structure schliesst Du die Verwendung von vornherein aus, ohne einen Mehrwert zu haben.zu 2)
Auf Redim solltest Du verzichten, das stammt aus einer anderen Zeit (VB Classic) und produziert nur reichlich Overhead
(und ebenfalls ohne Mehrwert).Ein interpolierter Aufbau würde könnte z. B. so aussehen:
Public Class Frage Public Property Verwendet As Boolean Public Property Bereich As String Public Property SGrad As String Public Property Frage As String Public Property Antworten As New List(Of String) Public Property RAntwort As Integer End Class Public Class Fragen Inherits List(Of Frage) Public Shared Function Create() As Fragen Dim liste = New Fragen() From { New Frage With { .Bereich = "X1", .SGrad = "X2", .Frage = "Struktur oder Klasse", .RAntwort = 1, .Antworten = New List(Of String) From {"Struktur", "Klasse", "Keines von beiden"} }, New Frage With { .Bereich = "X1", .SGrad = "X2", .Frage = "Array oder Auflistung", .RAntwort = 1, .Antworten = New List(Of String) From {"Array", "Auflistung", "Keines von beiden"} } } ' Beispiel für dynamische Erzeugung Dim nochneFrage = New Frage With {.Bereich = "X1", .SGrad = "X2", .Frage = "Noch eine Frage"} nochneFrage.Antworten.Add("1. Antwort") nochneFrage.Antworten.Add("2. Antwort") liste.Add(nochneFrage) Dim weitereFrage = New Frage With {.Bereich = "X1", .SGrad = "X2", .Frage = "Eine dritte Frage"} weitereFrage.Antworten = New List(Of String) From {"Keine Antwort", "Eine Antwort"} weitereFrage.Antworten.Add("Weiss ich nicht.") liste.Add(weitereFrage) Dim ohneAntwort = New Frage With {.Bereich = "X1", .SGrad = "X2", .Frage = "Eine Frage ohne Antworten"} liste.Add(ohneAntwort) Return liste End Function ' Fürs Testen... Friend Shared Sub Test() Dim alleFragen = Fragen.Create() For Each f In alleFragen Console.WriteLine("Frage: {0}, Antworten: {1}", f.Frage, f.Antworten.Count) For Each a In f.Antworten Console.WriteLine(" Antwort: " & a) Next Next End Sub End Class
Ich habe die Fragen zu einer Auflistung von Frage gemacht, die von List(T) erbt.So ist eine Frage eine eigenständige Klasse.
Und könnte (als reine Zukunftsmusik) um INotifyPropertyChanged ergänzt werden,
so dass man die Datenbindung von Windows Forms nutzen könnte.Aus Read habe ich Create gemacht, weil es besser die Funktion beschreibt.
Dort sind einige Varianten fürs statische wie dynamische Erzeugen gezeigt.
Mit Fragen.Test kannst Du das Ergebnis davon sehen.Wenn Du später weitere Funktionen hast, die die gesamte Auflistung (alle Fragen) betreffen,
wären sie in Fragen besser aufgehoben.
Funktionen die wiederum nur bei einer Frage benötigt werden gehören dorthin.Gruß Elmar
-
Servus Elmar,
danke für deine Geduld, das werde ich testen ... und dabei was lernen, zur zeit sieht das bei mir noch so aus ...
Die Daten werden nur gelesen und sind statisch, also ohne Änderungen
Public Structure Fragen Public Verwendet As Boolean Public Bereich As String Public SGrad As Int16 Public Frage As String Public Antworten() As String Public RAntwort As Int16 End Structure Public xFragen(35) As Fragen Public Sub read() Dim i As Int16 = 0 Dim myFileInfo As New IO.FileInfo(System.AppDomain.CurrentDomain.BaseDirectory & "Data\Quiz_Fragen.dat") ' Nun schauen wir nach ob eine Textdatei existiert If Not myFileInfo.Exists Then ' Wenn nicht, Meldung Beep() End If ' Erst benötigen wir eine Variable die den Text aufnimmt Dim textline As String ' Nun über StreamReader einlesen (wir verwenden Using, das räumt sich selbst auf) Using lese As New System.IO.StreamReader(System.AppDomain.CurrentDomain.BaseDirectory & "Data\Quiz_Fragen.dat", System.Text.Encoding.Default) Do While Not lese.EndOfStream textline = lese.ReadLine Dim sArray() As String ReDim xFragen(i).Antworten(3) sArray = Split(textline, "|") xFragen(i).Verwendet = False xFragen(i).Bereich = sArray(1) xFragen(i).SGrad = sArray(2) xFragen(i).Frage = sArray(3) xFragen(i).Antworten(0) = sArray(4) xFragen(i).Antworten(1) = sArray(5) xFragen(i).Antworten(2) = sArray(6) xFragen(i).Antworten(3) = sArray(7) xFragen(i).RAntwort = sArray(8) i = i + 1 Loop End Using End Sub
ich sag mal danke .... mfg eem monarch -
Hallo,
da ändert sich (fast) gar nichts.
Ergänze den Code (bzw. ändere Testen):Public Sub Read() Read(Path.Combine(Application.StartupPath, "Fragen.dat")) End Sub Public Sub Read(ByVal fileName As String) If Not File.Exists(fileName) Then Return End If ' .NET 4 For Each eingabe In File.ReadLines(fileName) Dim felder = eingabe.Split("|"c) Dim frage = New Frage() With { .Bereich = felder(1), .SGrad = felder(2), .Frage = felder(3), .Antworten = New List(Of String) From {felder(4), felder(5), felder(6), felder(7)}, .RAntwort = Integer.Parse(felder(8)) } Me.Add(Frage) Next End Sub ' Fürs Testen... Friend Shared Sub Test() 'Dim alleFragen = Fragen.Create() Dim alleFragen = New Fragen() alleFragen.Read() For Each f In alleFragen Console.WriteLine("Frage: {0}, Antworten: {1}", f.Frage, f.Antworten.Count) For Each a In f.Antworten Console.WriteLine(" Antwort: " & a) Next Next End Sub
wobei ich einen andere Pfadangabe verwendet habe, mit dem Input:|X0|X1|Struktur oder Klasse|Struktur|Klasse|Keines von beiden||1 |X1|X2|Array oder Auflistung|Array|Auflistung|||1 |X2|X3|Frage ohne Antwort|1. Antwort|2. Antwort|3. Antwort|4. Antwort|5 |X2|X4|Frage ohne Antwort|||||0
Willst Du die Löcher (fehlende Antworten) loswerden, wirf
.Antworten = New List(Of String) From {felder(4), felder(5), felder(6), felder(7)},
oben aus dem Konstruktor raus und füge nur die nicht-leeren hinzu, z. B.
For Each antwort In {felder(4), felder(5), felder(6), felder(7)} If Not String.IsNullOrEmpty(antwort) Then frage.Antworten.Add(antwort) End If Next
Gruß Elmar
- Als Antwort markiert Monarch-Falter Donnerstag, 19. Januar 2012 16:42
-
Hallo Elmar,
das habe ich doch gerne gemacht.
Gruß
Hannes
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/