Ich möchte wissen, ob ein Äquivalent (.net) existierenVB6 äquivalent zur Liste <someclass>
list<somefixedclass>
in VB6
Ich weiß, die Sammlung in VB6 existieren, aber es nutzt Objekt (Variante) statt ein bestimmtes Objekt.
danke.
Ich möchte wissen, ob ein Äquivalent (.net) existierenVB6 äquivalent zur Liste <someclass>
list<somefixedclass>
in VB6
Ich weiß, die Sammlung in VB6 existieren, aber es nutzt Objekt (Variante) statt ein bestimmtes Objekt.
danke.
Es gibt keine direkte Entsprechung in VB 6 zu dem generischen List<T>
in VB.NET. In VB 6 gibt es jedoch eine Collection
, die ähnliche Funktionen bietet. Der Hauptunterschied ist, dass ein VB 6 Collection
nicht stark typisiert ist, was bedeutet, dass alle Objekte als Variants
in der Sammlung gespeichert werden. In einigen Fällen kann dies von Vorteil sein, da Sie damit viele verschiedene Datentypen in derselben Sammlung speichern können. VB verwendet dieses Objekt intern. Es ist einfach genug, ein Collection
und up-Cast-Objekte zu verwenden, wie sie aus der Klasse abgerufen werden, aber es gibt wenig, was Sie tun können. Es ist nicht möglich, in der VB-Laufzeit stark typisierte Auflistungen zu implementieren.
Das besagt, es gibt eine Problemumgehung, die Sie implementieren können. Ähnlich wie Collections in früheren Versionen von VB.NET implementiert wurden, bevor Generics eingeführt wurden, können Sie die Collection
in eine Klasse einbinden, in der der einzige Zugriff auf das interne Collection
durch Methoden erfolgt, die Sie aus dieser Klasse bereitstellen. Dieses Designmuster wird üblicherweise als "benutzerdefinierte Sammlung" bezeichnet.
Dies hat den Vorteil, dass Casting automatisch gehandhabt wird und die Benutzer Ihres Codes davon ablenken, sich Gedanken über Implementierungsdetails zu machen. Es kümmert sich um die (allzu wahrscheinliche) Möglichkeit, dass Sie zur Laufzeit eine Sammlung durchlaufen, die nur einen Objekttyp enthalten soll, aber versehentlich einen zweiten, inkompatiblen Objekttyp hinzugefügt hat, der Ihren Code verursacht eine Ausnahme auslösen Der Nachteil ist natürlich, dass Sie die meisten Funktionen, die bereits vom Collection
-Objekt bereitgestellt werden, in Form von öffentlichen Methoden in Ihrer benutzerdefinierten Sammlung erneut implementieren müssen.
Hier ist ein Beispiel dafür, wie Sie darüber gehen könnte:
Public Class CustomerCollection
''#Internal collection, exposed by this class
Private m_Customers As Collection
Private Sub Class_Initialize()
''#Set up the internal collection
Set m_Customers = New Collection
End Sub
Public Sub Add(ByVal cust as Customer, Optional ByVal key as String)
''#Add the Customer object to the internal collection
If IsMissing(key) Then
m_Customers.Add cust
Else
m_Customers.Add cust, key
End If
End Sub
Public Property Get Count() As Integer
''#Return the number of objects in the internal collection
Count = m_Customers.Count
End Property
Public Sub Remove(ByVal index As Variant)
''#Remove the specified object from the internal collection,
''# either by its index or its key
m_Customers.Remove index
End Sub
Public Function Item(ByVal index As Variant) as Customer
''#Return the specified object from the internal collection,
''# either by its index or its key
Set Item = m_Customers.Item(index)
End Function
Public Sub Clear()
''#Removes all objects from the internal collection
Set m_Customers = New Collection
End Sub
End Class
Beachten Sie, dass, um die benutzerdefinierte Sammlung Item
Eigenschaft als die Sammlung der Standardmethode zu setzen (wie der eingebaute in Collection
Objekt), müssen Sie folgen diese Schritte in der VB 6 IDE:
Aus dem Menü "Extras" auf "Prozedurattribute"
Wählen Sie den Namen Ihrer benutzerdefinierten Klasse aus dem Kombinationsfeld "Name".
Wenn das Dialogfeld angezeigt wird, klicken Sie auf die Schaltfläche "Erweitert".
Wählen Sie im Kombinationsfeld "Prozedur-ID" den Eintrag "(Standard)".
Klicken Sie auf „OK“
Wenn Sie auch Aufzählung Ihrer benutzerdefinierten Klasse ermöglichen, möchte die For Each
Syntax (auch wie die eingebaute in Collection
Objekt), Sie hinzufügen NewEnum
Funktion, um Ihre eigene Klasse:
Public Property Get NewEnum() As IUnknown
''#Provides support for enumeration using For Each
Set NewEnum = m_Customers.[_NewEnum]
End Property
Sobald Sie das getan haben, was Sie brauchen VB anweisen, diese Eigenschaft zu verwenden:
nach wie vor, öffnen Sie die „Prozedurattribute“ Dialog aus dem Menü „Extras“
Wählen Sie den Namen der benutzerdefinierten Klasse aus der „Name“ Combo-Box.
Wenn das Dialogfeld angezeigt wird, klicken Sie auf die Schaltfläche "Erweitert".
Geben Sie im Kombinationsfeld "Prozedur-ID" die Zahl "-4" ein.
Klicken Sie auf "OK"
VB6 ist eine alte Sprache. Es enthält keine Template-ähnlichen Typen wie in modernen Sprachen (C++, C#, Java). Sie müssen also Ihre Objekte als Varianten in der Sammlung speichern und sie später wieder in Ihren Objekttyp umwandeln.
Ich arbeite normalerweise mit C# in verschiedenen Projekten, aber für eigenständige ausführbare Dateien. Warum?. Weil .net ist langsam (in den meisten Fällen), kann es leicht dekompiliert werden, es benötigt das net-Framework, es funktioniert nicht mit den meisten Betriebssystemen, vb6 kann von Windows95 zu Linux (mit Wein ohne viel Aufwand) laufen. Und Java für den Stand allein ausführbar ist bestenfalls "funky". Meine andere Option ist Delphi und C++, aber es ist eine andere Geschichte. – magallanes
Ihre Argumentation ist falsch. VB6 fehlt generische Typen, nicht weil es eine alte Sprache ist (was nicht der Fall ist, C++ ist viel älter), sondern weil es eine bewusste Entscheidung war, diese Art von Komplexität der Sprache zu entziehen, die eine völlig andere Nische hat. – GSerg
Beachten Sie, dass ich nicht downvote, weil -2 mehr als niedrig genug für einen Beitrag ist, der tatsächlich die richtige Antwort bietet.Aber ich denke, es lohnt sich, darauf hinzuweisen, dass wir als Programmierer * nicht * den Luxus haben, die Sprache zu wählen, die wir wollen. Ihr Vorschlag ist nicht wirklich hilfreich und wahrscheinlich frustrierender als alles andere. Und für das, was es wert ist, erinnern Sie sich möglicherweise an das Leben vor Generika in diesem "alten" C# 1.1 ... –
EDIT: wenn Cody Grays Lösung für Ihre Bedürfnisse zu sperrig, Sie könnten versuchen, anstatt die „armen Mannes Liste“ Lösung wie folgt:
Dim l() as somefixedclass
Redim l(0)
'...
'increase size dynamically:
Redim Preserve l(ubound(l)+1)
'...
Natürlich ein List<somefixedclass>
(in C#) oder ein List(Of somefixedclass)
in VB.NET ist viel "benutzerfreundlicher", weil es Methoden wie Suchen, Entfernen, AddRange und einige andere hilfreiche Dinge hat. Das alte VB6-Konstrukt geht sehr schlecht mit dem Fall "leere Liste" um. Nicht zu vergessen, Liste < ..> Erhöhung hat eine viel bessere Leistung für große Listen (Größe> 1000).
ja, es ist eine andere Alternative, danke – magallanes
Dies ist eine plausible Lösung, außer dass die Leistung von 'Redim Preserve' kann Killer sein, wenn Sie finden, rufen Sie es viel. Die Verwendung von Arrays oder 'Collection' in VB6 ist eine wichtige Entscheidung für das Design. Wenn Sie die Anzahl der Elemente, die Sie im Voraus haben, kennen (oder sich annähern können), sollten Sie sich für ein Array entscheiden. Die Leistung ist etwas besser als eine "Sammlung", aber wenn Sie Objekte dynamisch hinzufügen und entfernen, ist eine 'Sammlung' wahrscheinlich die beste Wahl. –
@Cody Gray: ja, Leistung kann auf diese Weise schlecht werden. In den meisten realen Programmen, die ich in den letzten 5 Jahren in Excel-VBA geschrieben habe, ist der 98% ige Fall einer Liste eine Liste mit weniger als 500 Einträgen, wobei diese Lösung vollkommen ausreichend ist. –
Hier ist unsere Implementierung von Arraylist. Sie können es als Basis (nicht durch Vererbung natürlich, aber durch Komposition wie in CodyGray's Antwort ausgedrückt) für eine stark typisierte Klasse verwenden, aber wenn Sie keine Typsicherheit benötigen, ist es viel besser als die Collection-Klasse.
Option Explicit
Private mavInternalArray() As Variant
Private mlArraySize As Long
Private mlCount As Long
Private mlGrowSize As Long
Private mfZeroIndex As Boolean
'---------------------------------------------------------------------------------------
' Procedure Clear
'---------------------------------------------------------------------------------------
Public Sub Clear()
Dim index As Long
For index = 0 To mlCount - 1
If IsObject(mavInternalArray(index)) Then
Set mavInternalArray(index) = Nothing
End If
Next index
mlCount = 0
End Sub
'---------------------------------------------------------------------------------------
' Procedure Swap
'---------------------------------------------------------------------------------------
Public Sub Swap(Index1 As Long, index2 As Long)
Dim vTmp As Variant
If IsObject(mavInternalArray(index2)) Then
Set vTmp = mavInternalArray(index2)
Else
vTmp = mavInternalArray(index2)
End If
If IsObject(mavInternalArray(Index1)) Then
Set mavInternalArray(index2) = mavInternalArray(Index1)
Else
mavInternalArray(index2) = mavInternalArray(Index1)
End If
If IsObject(vTmp) Then
Set mavInternalArray(Index1) = vTmp
Else
mavInternalArray(Index1) = vTmp
End If
End Sub
Public Property Get ZeroIndex() As Boolean
ZeroIndex = mfZeroIndex
End Property
Public Property Let ZeroIndex(fZeroIndex As Boolean)
mfZeroIndex = fZeroIndex
End Property
Public Property Get GrowSize() As Long
GrowSize = mlGrowSize
End Property
Public Property Let GrowSize(lNewSize As Long)
Debug.Assert lNewSize > 0
mlGrowSize = lNewSize
End Property
Private Sub Class_Initialize()
mlGrowSize = 50
mlArraySize = mlGrowSize
mfZeroIndex = True
mlCount = 0
ReDim mavInternalArray(0 To mlGrowSize - 1)
End Sub
'---------------------------------------------------------------------------------------
' Procedure Remove
'---------------------------------------------------------------------------------------
Public Sub Remove(index As Long)
Dim index2 As Long
For index2 = index To mlCount - 2
If IsObject(mavInternalArray(index2 + 1)) Then
Set mavInternalArray(index2) = mavInternalArray(index2 + 1)
Else
mavInternalArray(index2) = mavInternalArray(index2 + 1)
End If
Next index2
If mlCount <= 0 Then
Exit Sub
End If
mlCount = mlCount - 1
If IsObject(mavInternalArray(mlCount)) Then
Set mavInternalArray(mlCount) = Nothing
Else
mavInternalArray(mlCount) = False
End If
End Sub
'---------------------------------------------------------------------------------------
' Procedure Items
'---------------------------------------------------------------------------------------
Public Function Items(index As Long) As Variant
If Not mfZeroIndex Then
index = index - 1
End If
If index < mlCount And index >= 0 Then
If IsObject(mavInternalArray(index)) Then
Set Items = mavInternalArray(index)
Else
Items = mavInternalArray(index)
End If
End If
End Function
Public Sub SetItem(index As Long, Item As Variant)
If Not mfZeroIndex Then
index = index - 1
End If
If IsObject(Item) Then
Set mavInternalArray(index) = Item
Else
mavInternalArray(index) = Item
End If
End Sub
'---------------------------------------------------------------------------------------
' Procedure Add
'---------------------------------------------------------------------------------------
Public Function Add(vItem As Variant) As Long
mlCount = mlCount + 1
If mlCount > mlArraySize Then
mlArraySize = mlArraySize + mlGrowSize
ReDim Preserve mavInternalArray(0 To mlArraySize - 1)
End If
If IsObject(vItem) Then
Set mavInternalArray(mlCount - 1) = vItem
Else
mavInternalArray(mlCount - 1) = vItem
End If
Add = mlCount - 1
End Function
'---------------------------------------------------------------------------------------
' Procedure ItemArray
'---------------------------------------------------------------------------------------
Public Function ItemArray() As Variant
Dim vReturnArray As Variant
vReturnArray = mavInternalArray
ReDim Preserve vReturnArray(0 To mlCount - 1)
ItemArray = vReturnArray
End Function
Public Function Count() As Long
Count = mlCount
End Function
'---------------------------------------------------------------------------------------
' Procedure Insert
'---------------------------------------------------------------------------------------
Public Function Insert(index As Long, vItem As Variant) As Long
Dim index2 As Long
'Make sure array is large enough for a new item
mlCount = mlCount + 1
If mlCount > mlArraySize Then
mlArraySize = mlArraySize + mlGrowSize
ReDim Preserve mavInternalArray(0 To mlArraySize - 1)
End If
'Bump all the items with a higher index up one spot
If index >= mlCount - 1 Then
If IsObject(vItem) Then
Set mavInternalArray(mlCount - 1) = vItem
Else
mavInternalArray(mlCount - 1) = vItem
End If
Else
For index2 = mlCount - 1 To index + 1 Step -1
If IsObject(vItem) Then
Set mavInternalArray(index2) = mavInternalArray(index2 - 1)
Else
mavInternalArray(index2) = mavInternalArray(index2 - 1)
End If
Next index2
If IsObject(vItem) Then
Set mavInternalArray(index) = vItem
Else
mavInternalArray(index) = vItem
End If
End If
Insert = mlCount - 1
End Function
Public Sub Clone(ByRef cDestinationDynamicArray As clsDynamicArray)
Dim index As Long
If cDestinationDynamicArray Is Nothing Then
Set cDestinationDynamicArray = New clsDynamicArray
End If
cDestinationDynamicArray.Clear
For index = 0 To mlCount - 1
Call cDestinationDynamicArray.Add(mavInternalArray(index))
Next index
End Sub
Public Property Get NewEnum() As IUnknown
''#Provides support for enumeration using For Each
Set NewEnum = m_Customers.[_NewEnum]
End Property
+1 Interessante Lösung. Nur aus Neugierde: Haben Sie dies als schneller für Add-Ons/Insertions als die 'Collection' Klasse bewertet? Oder auf welche Weise meintest du, dass es besser ist? –
In welcher Weise ist es besser? Die Sammlung kann sich ohne Ihr Wissen in ein Wörterbuch verwandeln. Dann ist Ihre Zählung, sagen wir 5, aber die Elemente sind (0,1,4,5,6) Sie erhalten einen Fehler, wenn Sie versuchen, auf Element 3 zuzugreifen und einen Fehler zu erhalten. Es ist auch schneller, wenn Sie GrowSize so einstellen, dass es für die Größe Ihres Arrays geeignet ist (yeah, es könnte sich wahrscheinlich verbessern, indem es jedes Mal, wenn es wächst, verdoppelt, aber das ist eine Mikrooptimierung, die den zusätzlichen Code nicht wert ist). Jedoch in diesen Tagen (als es geschrieben wurde, war die Geschwindigkeit einer CPU ungefähr 200Mhz) ist die Effizienz nicht das, was wichtig ist, keinen Fehler zu haben. –
+1. Meiner Meinung nach ist diese (richtige) Lösung in vielen Fällen hilfreich, aber in einigen anderen Fällen ist sie vielleicht etwas überdimensioniert. –
@Doc Brown: Einverstanden. Ausgezeichnete Wortwahl. –
+1 Aber erstellen Sie das Muster nicht selbst. Francesco Balena schrieb [CollectionClassMaster] (http://www.angryhacker.com/download/colclassmaster.zip), ein kostenloses Plug-in für die VB6 IDE, das es automatisch für Sie erledigt. Dies wird jetzt freundlicherweise von [AngryHacker] gehostet (http://angryhacker.com/blog/archive/2008/05/01/vb6-swiss-army-knife.aspx)) – MarkJ