2010-11-14 57 views
8

我想知道是否存在的当量(.NET)VB6相当于列出<someclass>

list<somefixedclass> 

我知道存在收集VB6,但它使用的对象(变体)

在VB6,而不是一个特定的对象。

感谢。

回答

21

在VB 6中没有与在VB.NET中找到的通用List<T>等效。但是,在VB 6中有这样一个东西,它提供了类似的功能。主要区别在于一个VB 6 Collection没有强类型,这意味着所有对象在集合中被存储为Variants。在某些情况下,这可能是有益的,因为它允许您在同一个集合中存储许多不同类型的数据,事实上,VB在内部使用此对象。使用Collection和上传对象,因为它们是从课堂中检索的,但很难做到。在VB运行时中不可能实现强类型的集合。

这就是说,您可以实施一种解决方法。类似于早期版本的VB.NET如何在实现泛型之前实现集合,可以将Collection包装到一个类中,其中只有通过您从此类中公开的方法访问内部Collection。这种设计模式通常被称为“定制集合”

这确实有自动处理转换的好处,并且减轻了代码的消费者不必记住像这样的实现细节。它需要处理在运行时循环遍历集合(很可能)的可能性,该集合只能包含一种类型的对象,但意外地添加了另一种不兼容的对象类型,这会导致您的代码抛出异常。当然,缺点是您必须以自定义集合上的公共方法的形式重新实现已由对象自己提供的大部分功能。

这里是你怎么可能去一个例子:

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 

需要注意的是,以自定义集合的Item属性设置为集合的默认方法(如内置Collection对象),您需要遵循这些步骤在VB 6 IDE:

  1. 从 “工具” 菜单上,单击 “过程属性”

  2. 从“名称”组合框中选择您的自定义班级的名称。

  3. 当出现对话框时,单击“高级”按钮。

  4. 在“程序ID”组合框中选择“(默认)”项目。

  5. 单击“确定”


如果您还想允许使用For Each语法(也喜欢内置Collection对象),您可以添加自定义类的枚举NewEnum功能,以您的自定义类:

Public Property Get NewEnum() As IUnknown 
    ''#Provides support for enumeration using For Each 
    Set NewEnum = m_Customers.[_NewEnum] 
End Property 

一旦你做到了这一点,你需要指示VB使用这个属性:

  1. 和以前一样,从“工具”菜单

  2. 打开“过程属性”对话框中,从“名称”组合框中选择自定义类的名称。

  3. 当出现对话框时,单击“高级”按钮。

  4. 在“程序ID”组合框中键入数字“-4”。

  5. 单击 “确定”

+0

+1。恕我直言,这个(正确的)解决方案在很多情况下都是有用的,但对于其他一些情况,它可能有点过大。 – 2010-11-14 14:32:28

+0

@Doc Brown:同意。优秀的文字选择。 – 2010-11-14 14:35:58

+2

+1但是不要自己创建样板。 Francesco Balena写了[CollectionClassMaster](http://www.angryhacker.com/download/colclassmaster.zip),这是VB6 IDE的一个免费插件,可以自动为您提供。 [AngryHacker](http://angryhacker.com/blog/archive/2008/05/01/vb6-swiss-army-knife.aspx)) – MarkJ 2010-11-14 20:00:25

0

VB6是一种古老的语言。它不包含像现代语言(C++,C#,Java)那样的模板类型。所以你将不得不将对象存储为集合中的变体,然后将它们转换回对象类型。

+0

我通常在各种项目中使用c#,但对于独立的可执行文件。为什么?。因为.net很慢(大多数情况下),它可以很容易地反编译,它需要网络框架,它不适用于大多数操作系统,vb6可以从windows95运行到linux(用wine不需要太多努力)。单独的可执行文件充其量是“质朴的”。我的其他选择是Delphi和C++,但它是另一回事。 – magallanes 2010-11-14 13:59:36

+4

你的推理是错误的。 VB6缺乏通用类型,并不是因为它是一种古老的语言(事实并非如此,C++更古老),而是因为它是一种有意识的决定,使这种复杂性远离具有完全不同利基的语言。 – GSerg 2010-11-14 14:04:25

+0

请注意,我没有downvote,因为-2对于确实提供正确答案的帖子来说足够低。但我认为值得指出的是,作为程序员,我们总是不会选择任何我们想要的语言。你的建议并不真正有帮助,可能比任何事情都更令人沮丧。而对于它的价值,你可能还记得那个“古代”C#1.1中的泛型之前的生活...... – 2010-11-14 14:33:08

2

编辑:如果科迪灰色的解决方案是适合您的需求也超大,你可以尝试,而不是“穷人的名单”的解决方案,具体如下:

Dim l() as somefixedclass 
Redim l(0) 

'... 
'increase size dynamically: 
Redim Preserve l(ubound(l)+1) 
'... 

当然,一个List<somefixedclass>(在C#)或List(Of somefixedclass)在VB.NET中更加“用户友好”,因为它具有Find,Remove,AddRange和其他一些有用的方法。旧的VB6构造非常不利于“空列表”的情况。不要忘记,列表< ..>增加对大列表(大小> 1000)有更好的性能。

+0

是的,这是另一种选择,谢谢 – magallanes 2010-11-14 14:33:45

+0

这是一个合理的解决方案,不同之处在于'Redim Preserve'的性能可能是杀手级的,如果你发现自己调用它很多。在VB 6中使用数组或者“Collection”是一个重要的设计决定,最好的建议是如果你知道(或者可以近似地)预先提供的项目数量,那么你应该选择一个数组。性能稍好于“集合”,但如果您要动态添加和删除对象,“集合”可能是最佳选择。 – 2010-11-14 14:35:15

+0

@Cody Gray:是的,性能可能会变坏。在我最近5年在Excel-VBA中编写的大多数真实世界的程序中,98%的列表情况是列表中少于500个条目的列表,其中此解决方案如果完全足够。 – 2010-11-14 14:42:28

4

下面是我们实现的ArrayList。对于强类型类,您可以将它用作基础(不是通过显然的继承,而是通过CodyGray的答案中表达的组合),但是如果您不需要类型安全性,则它比集合类好得多。

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 
+0

+1有趣的解决方案。出于好奇:你有没有比'Collection'类更快地添加/插入基准?或者你的意思是哪种方式更好? – 2010-11-16 06:04:08

+0

哪种方式更好?收藏可能会意外变成字典,而不知道。然后你的计数是5,但是这些项目是(0,1,4,5,6),当你尝试访问元素3并得到错误时,你会得到一个错误。另外,如果你将GrowSize设置为适合你数组的大小,它会更快(是的,它可以通过每次增长时增加一倍来提高自身,但这是一种微型优化,不值得额外的代码)。然而现在(写入CPU的速度大约是200Mhz)效率并不重要,没有错误。 – 2010-11-17 04:31:26