最近,我认为VB6的Collection不足以满足我的需求,因此我决定实现类似于C#的List<T>的功能。这是产生的类,我想知道是否可以使实现更好/更有效,尤其是使用InsertSort方法时;我也希望另一只眼睛检查出现的错误,看是否一切都有道理-这个主意不是抛出List<T>可能出现的所有错误,但我可能错过了抛出可能导致错误的错误。帮助可用性。

我已经在VB6代码中使用此List类不到一个星期了,而且说真的,这就像切面包以来最好的事情-能够内联添加项目太棒了,所有这些成员使Collection看起来非常无聊,并让我想实现一个键控版本,我想可以改用Dictionary


类定义和私有函数

和我编写的所有类一样,我先声明一个Private Type来定义该类封装的内容,然后创建一个私有类型的实例(称为this),并在其余代码中引用到this,与Me的含义不同(Me是指当前List类的立场,而this指的是封装的东西-您会注意到,我只在必要时才使用Me。公开或不公开-这样做将记录在API级别引发的错误,但没有任何实际目的。



 RaiseErrorXXXX 



公共属性

 Attribute VB_Name = "List"
Private Type tList
    Encapsulated As Collection
    ItemTypeName As String
End Type

Private this As tList
Option Explicit

Private Function IsReferenceType() As Boolean
    If Count = 0 Then Exit Function
    IsReferenceType = IsObject(this.Encapsulated(1))
End Function

Private Function IsComparable() As Boolean
    If IsReferenceType Then
        IsComparable = TypeOf First Is IComparable
    End If
End Function

Private Function CompareReferenceTypes(value As Variant, other As Variant) As Integer

    Dim comparable As IComparable

    If IsComparable Then

        Set comparable = value
        CompareReferenceTypes = comparable.CompareTo(other)

    Else

        RaiseErrorMustImplementIComparable "CompareReferenceTypes()"

    End If

End Function

Private Function CompareValueTypes(value As Variant, other As Variant) As Integer

    If value < other Then

        CompareValueTypes = -1

    ElseIf value > other Then

        CompareValueTypes = 1

    End If

End Function

Private Function IsEquatable() As Boolean
    If IsReferenceType Then
        IsEquatable = TypeOf First Is IEquatable
    End If
End Function

Private Function EquateReferenceTypes(value As Variant, other As Variant) As Boolean

    Dim equatable As IEquatable
    If IsEquatable Then

        Set equatable = value
        EquateReferenceTypes = equatable.Equals(other)

    Else

        Debug.Print "WARNING: Reference type doesn't implement IEquatable, using reference equality."
        EquateReferenceTypes = (ObjPtr(value) = ObjPtr(other))

    End If

End Function

Private Function EquateValueTypes(value As Variant, other As Variant) As Boolean

    EquateValueTypes = (value = other)

End Function

Private Function ValidateItemType(value As Variant)

    If this.ItemTypeName = vbNullString Then this.ItemTypeName = TypeName(value)
    ValidateItemType = IsTypeSafe(value)

End Function

Private Sub RaiseErrorUnsafeType(member As String, suppliedType As String)
    Err.Raise 13, StringFormat("{0}.{1}", ToString, member), _
                  StringFormat("Type Mismatch. Expected: '{0}', '{1}' was supplied.", this.ItemTypeName,  suppliedType)
End Sub

Private Sub RaiseErrorMustImplementIComparable(member As String)
    Err.Raise 5, StringFormat("{0}.{1}", ToString, member), "Invalid operation: method requires a list of numeric, date or string values, or a list of objects implementing the IComparable interface."
End Sub

Private Sub Class_Initialize()
    Set this.Encapsulated = New Collection
End Sub

Private Sub Class_Terminate()
    Set this.Encapsulated = Nothing
End Sub
  


公共方法/函数
那些按字母顺序列出:

 Public Property Get Item(ByVal Index As Long) As Variant
Attribute Item.VB_UserMemId = 0
'Gets the element at the specified index.

    If IsReferenceType Then
        Set Item = this.Encapsulated(Index)
    Else
        Item = this.Encapsulated(Index)
    End If

End Property

Public Property Let Item(ByVal Index As Long, ByVal value As Variant)
'Sets the element at the specified index.

    If Not IsTypeSafe(value) Then RaiseErrorUnsafeType "Item(Let)", TypeName(value)

    RemoveAt Index
    If Index = Count Then
        Add value
    Else
        Insert Index, value
    End If

End Property

Public Property Set Item(ByVal Index As Long, ByVal value As Variant)
'Sets the element at the specified index.

    If Not IsTypeSafe(value) Then RaiseErrorUnsafeType "Item(Set)", TypeName(value)

    RemoveAt Index
    If Index = Count Then
        Add value
    Else
        Insert Index, value
    End If

End Property

Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"
'Gets an enumerator that iterates through the List.

    Set NewEnum = this.Encapsulated.[_NewEnum]

End Property

Public Property Get Count() As Long

    Count = this.Encapsulated.Count

End Property
 



接口

由于相同的原因Public Sub Add(value As Variant) 'Adds an object to the end of the List. If Not ValidateItemType(value) Then RaiseErrorUnsafeType "Add()", TypeName(value) this.Encapsulated.Add value End Sub Public Sub AddArray(values() As Variant) 'Adds the specified elements to the end of the List. Dim value As Variant, i As Long For i = LBound(values) To UBound(values) Add values(i) Next End Sub Public Sub AddRange(ByRef values As List) 'Adds the specified elements to the end of the List. Dim value As Variant For Each value In values Add value Next End Sub Public Sub AddValues(ParamArray values()) 'Adds the specified elements to the end of the List. Dim value As Variant, i As Long For i = LBound(values) To UBound(values) Add values(i) Next End Sub Public Sub Clear() 'Removes all elements from the List. Do Until Count = 0 this.Encapsulated.Remove 1 Loop End Sub Public Function Contains(value As Variant) As Boolean 'Determines whether an element is in the List. Contains = (IndexOf(value) <> -1) End Function Public Function First() As Variant 'Returns the first element of the List. If Count = 0 Then Exit Function If IsReferenceType Then Set First = Item(1) Else First = Item(1) End If End Function Public Function GetRange(ByVal Index As Long, ByVal valuesCount As Long) As List 'Creates a copy of a range of elements in the source List. Dim result As List If Index > Count Then Err.Raise 9 'index out of range Dim lastIndex As Long lastIndex = IIf(Index + valuesCount > Count, Count, Index + valuesCount) Set result = New List Dim i As Long For i = Index To lastIndex result.Add Item(i) Next Set GetRange = result End Function Public Function IndexOf(value As Variant) As Long 'Searches for the specified object and returns the 1-based index of the first occurrence within the entire List. Dim found As Boolean Dim isRef As Boolean isRef = IsReferenceType Dim i As Long If Count = 0 Then IndexOf = -1: Exit Function For i = 1 To Count If isRef Then found = EquateReferenceTypes(value, Item(i)) Else found = EquateValueTypes(value, Item(i)) End If If found Then IndexOf = i: Exit Function Next IndexOf = -1 End Function Public Sub Insert(ByVal Index As Long, value As Variant) 'Inserts an element into the List at the specified index. Dim tmp As List Set tmp = GetRange(Index, Count) RemoveRange Index, Count Add value AddRange tmp End Sub Public Sub InsertArray(ByVal Index As Long, values() As Variant) 'Inserts the specified elements into the List at the specified index. Dim tmp As List Set tmp = GetRange(Index, Count) RemoveRange Index, Count AddArray values AddRange tmp End Sub Public Sub InsertRange(ByVal Index As Long, values As List) 'Inserts the specified elements into the List at the specified index. Dim tmp As List Set tmp = GetRange(Index, Count) RemoveRange Index, Count AddRange values AddRange tmp End Sub Public Sub InsertValues(ByVal Index As Long, ParamArray values()) 'Inserts the specified elements into the List at the specified index. Dim valuesArray() As Variant valuesArray = values InsertArray Index, valuesArray End Sub Public Function IsSortable() As Boolean 'Determines whether the List can be sorted. If Count = 0 Then Exit Function Dim firstItem As Variant If IsReferenceType Then Set firstItem = First Else firstItem = First End If IsSortable = IsNumeric(firstItem) _ Or IsDate(firstItem) _ Or this.ItemTypeName = "String" _ Or IsComparable End Function Public Function IsTypeSafe(value As Variant) As Boolean 'Determines whether a value can be safely added to the List. 'Returns true if the type of specified value matches the type of items already in the list, 'or it the type of specified value is a numeric type smaller than the type of items already in the list. 'This means a List<Long> can contain Integer values, but a List<Integer> cannot contain Long values. Dim result As Boolean 'most common cases: this.ItemTypeName isn't yet defined, or matches TypeName(value): result = this.ItemTypeName = vbNullString Or this.ItemTypeName = TypeName(value) If result Then IsTypeSafe = result: Exit Function 'all other cases demand more processing: IsTypeSafe = result _ Or this.ItemTypeName = "Integer" And StringMatchesAny(TypeName(value), "Byte") _ Or this.ItemTypeName = "Long" And StringMatchesAny(TypeName(value), "Integer", "Byte") _ Or this.ItemTypeName = "Single" And StringMatchesAny(TypeName(value), "Long", "Integer", "Byte") _ Or this.ItemTypeName = "Double" And StringMatchesAny(TypeName(value), "Long", "Integer", "Byte", "Single") _ Or this.ItemTypeName = "Currency" And StringMatchesAny(TypeName(value), "Long", "Integer", "Byte", "Single", "Double") End Function Public Function Last() As Variant 'Returns the last element of the List. If Count = 0 Then Exit Function If IsReferenceType Then Set Last = Item(Count) Else Last = Item(Count) End If End Function Public Function LastIndexOf(value As Variant) As Long 'Searches for the specified object and returns the 1-based index of the last occurrence within the entire List. Dim found As Boolean Dim isRef As Boolean isRef = IsReferenceType LastIndexOf = -1 If Count = 0 Then Exit Function Dim i As Long For i = 1 To Count If isRef Then found = EquateReferenceTypes(value, Item(i)) Else found = EquateValueTypes(value, Item(i)) End If If found Then LastIndexOf = i Next End Function Public Function Max() As Variant 'Returns the maximum value in the List. Dim isRef As Boolean isRef = IsReferenceType Dim largest As Variant Dim isLarger As Boolean Dim i As Long For i = 1 To Count If isRef Then If IsEmpty(largest) Then Set largest = Item(i) isLarger = CompareReferenceTypes(Item(i), largest) > 0 If isLarger Or IsEmpty(Max) Then Set largest = Item(i) Set Max = largest End If Else If IsEmpty(largest) Then largest = Item(i) isLarger = CompareValueTypes(Item(i), largest) > 0 If isLarger Or IsEmpty(Max) Then largest = Item(i) Max = largest End If End If Next End Function Public Function Min() As Variant 'Returns the minimum value in the List. Dim isRef As Boolean isRef = IsReferenceType Dim smallest As Variant Dim isSmaller As Boolean Dim i As Long For i = 1 To Count If isRef Then If IsEmpty(smallest) Then Set smallest = Item(i) isSmaller = CompareReferenceTypes(Item(i), smallest) < 0 If isSmaller Or IsEmpty(Min) Then Set smallest = Item(i) Set Min = smallest End If Else If IsEmpty(smallest) Then smallest = Item(i) isSmaller = CompareValueTypes(Item(i), smallest) < 0 If isSmaller Or IsEmpty(Min) Then smallest = Item(i) Min = smallest End If End If Next End Function Public Sub Reverse() 'Reverses the order of the elements in the entire List. Dim tmp As New List Do Until Count = 0 tmp.Add Item(Count) RemoveAt Count Loop AddRange tmp End Sub Public Sub Remove(ParamArray values()) 'Removes the first occurrence of specified object(s) from the List. Dim i As Long Dim Index As Long For i = LBound(values) To UBound(values) Index = IndexOf(values(i)) If Index <> -1 Then RemoveAt Index Next End Sub Public Sub RemoveAt(ByVal Index As Long) 'Removes the element at the specified index of the List. this.Encapsulated.Remove Index End Sub Public Sub RemoveRange(ByVal Index As Long, ByVal valuesCount As Long) 'Removes a range of elements from the List. Dim i As Long For i = Index To Index + valuesCount - 1 RemoveAt Index Next End Sub Public Sub Sort() 'Sorts the elements in the entire List. Dim tmp As List Dim minValue As Variant If Not IsSortable Then RaiseErrorMustImplementIComparable "Sort()" Dim isRef As Boolean isRef = IsReferenceType Set tmp = New List Do Until Count = 0 If isRef Then Set minValue = Min Else minValue = Min End If tmp.Add minValue Remove minValue Loop AddRange tmp End Sub Public Sub SortDescending() 'Sorts the elements in the entire List, in descending order. Dim tmp As List Dim maxValue As Variant If Not IsSortable Then RaiseErrorMustImplementIComparable "SortDescending()" Dim isRef As Boolean isRef = IsReferenceType Set tmp = New List Do Until Count = 0 If isRef Then Set maxValue = Max Else maxValue = Max End If tmp.Add maxValue Remove maxValue Loop AddRange tmp End Sub Public Function ToArray() As Variant() 'Copies the elements of the List to a new array. Dim result() As Variant ReDim result(1 To Count) Dim i As Long If Count = 0 Then Exit Function If IsReferenceType Then For i = 1 To Count Set result(i) = Item(i) Next Else For i = 1 To Count result(i) = Item(i) Next End If ToArray = result End Function Public Function ToString() As String 'Returns a string that represents the current List object. ToString = StringFormat("{0}<{1}>", TypeName(Me), Coalesce(this.ItemTypeName, "Variant")) End Function 需要它们,因此List使用两个从C#改编而成的接口,即IComparableIEquatable-我相信如果我从MultiUse更改实例化,它们也将正常工作。到PublicNotCreatable,但这是我的VB6知识的一个模糊领域,因此我将其保留为:

IComparable: > List<T>


IEquatable:

 Option Explicit

Public Function CompareTo(other As Variant) As Integer
End Function
 



该类代码中的各处也使用了一些辅助函数-我不是要对此进行复习,但是如果您有兴趣了解更多内容,请参见Option Explicit Public Function Equals(other As Variant) As Boolean End Function 是自定义C#样式的VB6 / VBA此处介绍的StringFormat的实现,string.Format()是此处介绍的自定义字符串帮助器函数,StringMatchesAny是一个简单的null替换函数,将空字符串视为null值。

评论

我认为Add()应该带有一个ParamArray并调用AddArray(),因此AddValues()可以像Remove()一样作为冗余删除。 ...而且我可能错过了RemoveArray()方法。还是“过载”成员太多?

一件事:VBA不支持属性NewEnum.VB_MemberFlags =“ 40”。旨在从“对象浏览器”和Intelli-sense中隐藏成员,但无效。

@ vba4all确实如此。但是此代码最初是用VB6编写的;)

没问题。知道是否可以在VBA中隐藏成员吗? (不过不是通过COM-常规的VBA类成员)

@MarkHurd是。但是用户代码无法隐藏,似乎他们“压低”了VBE以致无法识别会隐藏它的成员属性。

#1 楼

好吧,在过去的两天中,仔细检查了代码并对此进行了思考。就实现而言,除了一些挑剔的事情之外,我看不到我会改变的很多东西(您在上面的答案中没有指出)。首先,是使用this变量标识符。除了模仿.NET关键字外,我找不到任何能证明命名和数据结构合理的东西。对于VB6程序员来说,Me关键字(在编写C#一段时间后听起来很荒谬)是显而易见的-this则不是。我个人会坚持使用单个成员变量而不是Type,但是如果使用Type,我会使用类似memberData的名称。您不得不在帖子中解释this在班级中所指的事实是一个危险信号,因为它不是立即显而易见的。隐喻没有直接映射到VB6上下文,但是这一隐喻来自相反的方向(并属于“引发错误”类别)。 .NET程序员会希望非类型安全的分配在编译时而不是运行时失败。例如,VB6中的此代码段编译并运行时没有任何抱怨: />
因此,如果要强制执行类型安全,则更好的元解决方案是:如果可以避免,则不要使用Variant类型,或者使用IDE插件来确保您的分配是类型安全的。如果要简单地复制.NET List对象的功能,则这是完全不同的事情(顺便说一句,它既有用又执行良好)。

暂且不谈,我们来谈谈“更好/更高效”的一面。鉴于VB6中的Collection对象只不过是一个荣耀的数组(有4种方法-认真吗?),我将完全跳过它并直接包装一个数组。绝大多数此类仅将Collection用于存储空间,并且其目的是确保强类型化这一事实使内存管理变得更加容易。请注意,我不推荐使用Variants数组,并且有进入StackOverflow领域的风险。

VB6基于Window COM,并使用SAFEARRAY结构在内部存储其所有数组。这(大大简化了)定义了每个数组元素的大小,跟踪每个维度中元素的数量,存储了两个COM标志,并保存了指向数组数据的指针。由于VB6是基于COM的,因此它还具有一些未记录的功能,例如用于指针解析和操纵的功能,并且可以直接访问Windows API。这使您能够使用内存复制操作在数组的中间进行插入和删除操作,而不是遍历数组或Collection。 />
Dim first as Variant
Dim second as Variant

first = "String"
second = 1234

first = second

'First is now an integer.
Debug.Print(TypeName(first))


这种方法的优点在于,因为您现在在变量中具有数组的基础数据结构,所以只需将pvData指针更改为已存在的任何内存即可。分配,并将cbElements设置为SizeOf()列表的数据类型。然后,一个Add()函数只是将存储空间从插入偏移量中移出一个更高的元素,然后放入新项,而Remove()则相反。真正使人眼花is乱的原因是,您可以将Variant指向SafeArray,而VB6甚至不会闪烁,因为这正是它所期望的。

关于现在,您可能想知道我什么时候开始打字。给我第二个,因为我想先浏览Variants。同样,请记住,我们正在处理的是COM对象,而不严格是VB对象。 Microsoft专门将Variants放入COM中,以允许松散类型的语言通过API向强类型语言进出数据。它的工作方式是传递一个结构,该结构包括接收API确定底层数据表示所需的所有信息。由于VB6仅实现了Variant可以表示的可用数据类型的很小的子集(请参阅MSDN链接后面的几句话),可以想像地强制实施VB6甚至不了解的数据类型。

您所要做的就是将Variant作为内存结构进行检查,而不是将其传递给内置的TypeName()函数。无论如何,这基本上就是它正在做的事情(尽管我无法验证这一点,但我相信强制转换函数使用Variant的并集来确定Variant是否可以强制转换为强类型。通过直接检查这些内容,您可以绕过VB运行时,也可以避免使用TypeName()涉及的所有字符串处理。本文是一个不错的起点,尽管大多数链接似乎都已消失。 ToString函数,您始终可以挂钩VB运行时dll本身,并拦截对本机VB函数的函数调用。我不会亲自在生产代码中执行此操作,但是如果您想真正地了解内部原理,则可以在此处获得一个好的开始。向下滚动并阅读有关蹦床功能的信息。我从没钩过VB运行时本身,但是只要您真正小心地在改组其内存时使用的功能,它就不会与其他dll有所区别。


如果尝试这种方法,则在调试时至少会使IDE崩溃一次。养成在不先保存源代码的情况下手动处理内存时不要启动调试会话的习惯。

#2 楼

 Public Function ToString() As String
'Returns a string that represents the current List object.

    ToString = StringFormat("{0}<{1}>", TypeName(Me), _
                                        Coalesce(this.ItemTypeName, "Variant"))

End Function
 


这意味着当List为空或"List<Variant>"时,此this.ItemTypeName的字符串表示形式为vbNullString

此函数应该放在最顶部:

 Private Function ValidateItemType(value As Variant)

    If this.ItemTypeName = vbNullString Then this.ItemTypeName = TypeName(value)
    ValidateItemType = IsTypeSafe(value)

End Function
 


这是字符串所在的位置List的表示形式不再是"List<Variant>",而变成List<T>


鉴于此信息,IsReferenceType函数中存在一个缺陷,如果该列表最初包含对象然后被清空,则可能返回错误结果这样Count = 0

 Private Function IsReferenceType() As Boolean
    If Count = 0 Then Exit Function
    IsReferenceType = IsObject(this.Encapsulated(1))
End Function
 


正确的代码应为:

 Private Function IsReferenceType() As Boolean
    If this.ItemTypeName = vbNullString Then Exit Function
    IsReferenceType = IsObject(this.Encapsulated(1))
End Function
 



在以下摘录中:

 Private Function IsComparable() As Boolean
    If IsReferenceType Then
        IsComparable = TypeOf First Is IComparable
    End If
End Function

Private Function IsEquatable() As Boolean
    If IsReferenceType Then
        IsEquatable = TypeOf First Is IEquatable
    End If
End Function
 


假定只有引用类型才能实现q43120 79q和IComparable,这在VB6中是正确的。因此,IEquatableCompareValueTypes函数的存在有些尴尬,但是它们的用法使人读起来很愉快:
/>

EquateValueTypes属性的getter中的 If isRef Then '... isSmaller = CompareReferenceTypes(Item(i), smallest) < 0 '... Else '... isSmaller = CompareValueTypes(Item(i), smallest) < 0 '... End If 设置使该getter为类型的默认属性,使得Attribute Item.VB_UserMemId = 0也可以通过Item访问。酷的东西。更好的是:

 Item(i) 


Me(i)指示VB在Public Property Get NewEnum() As IUnknown Attribute NewEnum.VB_UserMemId = -4 Attribute NewEnum.VB_MemberFlags = "40" 'Gets an enumerator that iterates through the List. Set NewEnum = this.Encapsulated.[_NewEnum] End Property 循环结构中使用此方法;这使Attribute NewEnum.VB_UserMemId = -4能够执行其操作:

 For Each 



给定AddRange(values As List),我认为For Each value In values Add value Next 可以轻松替换AddArray(values() As Variant)-如果仅添加1个值,则可以使用这两种方法,这使它成为一个模糊的API。 AddValues(ParamArray values())Add(value As Variant)Add应该重写如下:

 AddRange 



AddArray (无论使用何处)都是Public Sub Add(ParamArray values()) 'Adds the specified element(s) to the end of the List. Dim valuesArray() As Variant valuesArray = values AddArray valuesArray End Sub Public Sub AddRange(values As List) 'Adds the specified elements to the end of the List. AddArray values.ToArray End Sub Public Sub AddArray(values() As Variant) 'Adds the specified elements to the end of the List. Dim value As Variant, i As Long For i = LBound(values) To UBound(values) If ValidateItemType(value) Then this.Encapsulated.Add values(i) Else RaiseErrorUnsafeType "AddArray()", TypeName(value) End If Next End Sub 的机会,而不是返回空的If Count = 0 Then Exit Function或无意义的RaiseErrorListContainsNoElement值。 Variant应该消失并替换为:

 False 



Insert(ByVal Index As Long, value As Variant)在某种程度上是多余的,并且InsertValues(ByVal Index As Long, ParamArray values())变量仅隐藏意图-访问第一个项并不足够昂贵以承受这种可读性(此外,不会在循环中调用它),因此可以像这样重写Add,然后再次AddValuesInsertValues的机会:

 Public Sub Insert(ByVal Index As Long, ParamArray values())
'Inserts the specified element(s) into the List at the specified index.

    Dim valuesArray() As Variant
    valuesArray = values

    InsertArray Index, valuesArray

End Sub
 



IsSortable很有趣。它可以工作,但有点太僵硬,需要付出更多的努力才能接受firstItemIsSortable()范围内的If Count = 0 Then Exit Function值,依此类推。对RaiseErrorListContainsNoElementPublic Function IsSortable() As Boolean 'Determines whether the List can be sorted. If Count = 0 Then RaiseErrorListContainsNoElement "IsSortable()" If IsReferenceType Then IsSortable = IsComparable Else IsSortable = IsNumeric(First) _ Or IsDate(First) _ Or this.ItemTypeName = "String" End If End Function 进行了更改,但是IsTypeSafe打破了以LongInteger建立的命名约定,它们都以List<Integer>作为参数。由于Remove(ParamArray values())应该保留其.net Add的含义,因此InsertRemoveRange应该重命名为AddRangeInsertRange,这与ListRemoveRange是一致的。 >

评论


\ $ \ begingroup \ $
如果我可以更改某些东西,则可以稍微修改IndexOf()方法。请参阅我的答案以获取有关如何更改IndexOf()和Contains()的线索,您可以消除一些循环,以加快速度。
\ $ \ endgroup \ $
–user28366
2014年1月15日在8:29



#3 楼


可以通过实现Sort来优化IndexOfMin的实现,以使Min = Item(IndexOfMin)(带有一个空的List的警告),但是您可以在结尾处使用O(1)RemoveAt而不是O(n) Remove循环。当然,对于Do UntilIndexOfMaxMax同样。我会考虑制作SortDescendingIndexOfMin IndexOfMax,以允许其他代码使用相同的优化。 Public,不抛出错误。即List应该开始:

IsSortable = True
If Count = 0 Then Exit Function


您现有的ListIsSortable实现无需为此进行更改。

(编辑:添加了6个月稍后:-))Sort的实现实际上应该与SortDescending相同,但带有LastIndexOf

较小的小错误可读(无论如何从VB6 POV),并且当然要快得多: (我忘记了我的VB6优化:我知道IndexOf是标准习惯用法,但是For i = Count To 1 Step -1更快吗?否:我已经检查过,value快了9个数量级!