默认排序类组属性

Sort a group of Classes by default property

长话短说:

有什么方法可以将 class collection/list 传递给 排序算法,并将其传递给 return 排序列表(最好按 named/default class 属性)?

我最近学习了一些 Python,并且对 Sorted() 函数印象深刻,它可以对任何可迭代对象进行排序。对于数字,这很简单,但是对于 classes,可以分配比较方法 like this。该方法告诉比较运算符如何比较 class 的 2 个实例。除此之外,它还允许您使用内置排序算法对 class.

的集合进行排序

在VBA中,我已经成功模仿了一半。通过设置一个class'default memberAttribute,可以在[=上使用比较运算符(<=>=等) 58=]es 直接。举个例子class:

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "defaultProp"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Private randVal As Single

Public Property Get DefaultValue() As Single
    Attribute Value.VB_UserMemId = 0
    DefaultValue = randVal
End Property

Private Property Let DefaultValue(ByVal value As Single)
    randVal = value
End Property

Private Sub Class_Initialize()
    DefaultValue = Rnd()
End Sub

可以比较此 class 的两个实例:

 Dim instance1 As New defaultProp
 Dim instance2 As New defaultProp
 Debug.Print instance1.DefaultValue > instance2.DefaultValue
 Debug.Print instance1 > instance2 'exactly equivalent, as the DefaultValue has the correct Attribute

而且,如果我正在实施可以对值进行排序的 VBA 排序算法,那么按默认值*对 class 进行排序应该没有问题*。但是,我更愿意使用 builtin/library 排序算法(出于与任何人都相同的原因;清晰度、效率、正确的错误处理等)

*these algorithms 中的一个可以做到这一点,尽管必须修改以切换整个 class 回合,而不是它的值(通过添加 Sets)

由于 VBA 比较运算符没有问题,我假设库使用的任何内容都是如此。但是,当我尝试使用 ArrayList:

Sub testArrayList()
    Dim arr As Object
    Set arr = CreateObject("System.Collections.ArrayList")

    ' Initialise the ArrayList, for instance by generating random values
    Dim i As Long
    Dim v As defaultProp

    For i = 1 To 5
        Set v = New defaultProp
        arr.Add v 'no problem here
    Next i
    arr.Sort 'raises an error
End Sub

我收到一个错误

Failed to compare two elements in the array

所以这是怎么回事?这是我方法中的一个缺陷吗?默认属性是否没有进入 ArrayList?或者,无论用什么语言编写的库,比较运算符都不像 VBA 和 Python 使用的那样笨拙?任何关于尝试更多内置排序算法的建议也会很有用!

如果您将 DefaultValue 添加到 arr 它将起作用:

Sub testArrayList()
    '... code
    For i = 1 To 5
        Set v = New defaultProp
        arr.Add v.DefaultValue 
    Next i
    arr.Sort         
End Sub

显然ArrayList.Sort的实现有点奇怪,不喜欢比较对象和它们的默认值(找不到Sort()方法的实现)。虽然,这会完美地工作:

For i = 1 To 5
    Set v = New defaultProp
    arr.Add v
Next i    
Debug.Print arr(1) > arr(2)

这是一种可能的排序实现方式,按预期适用于 arr 对象。但是,它不是 ArrayList 库的一部分:

Public Function varBubbleSort(varTempArray As Object) As Object

    Dim varTemp                 As Object
    Dim lngCounter              As Long
    Dim blnNoExchanges          As Boolean

    Do
        blnNoExchanges = True
        For lngCounter = 0 To varTempArray.Count - 2
            If varTempArray(lngCounter) > varTempArray(lngCounter + 1) Then
                blnNoExchanges = False
                Set varTemp = varTempArray(lngCounter)
                varTempArray(lngCounter) = varTempArray(lngCounter + 1)
                varTempArray(lngCounter + 1) = varTemp
            End If
        Next lngCounter

    Loop While Not (blnNoExchanges)
    Set varBubbleSort = varTempArray

   On Error GoTo 0
   Exit Function

End Function

但是排序没问题:

这与 VBA 比较运算符无关,ArrayList 是一个 .NET class,所以当您使用它时,您就是在 .NET 世界中。

arr.Add v 'no problem here

您正在添加 defaultProp class 的实例;类型上有默认 属性 并不重要,.NET 不关心默认属性。如果你想对 DefaultValue 值进行排序,然后执行 arr.Add v.DefaultValuearr.Add (v) - 然后你的 ArrayList 将包含类型 Single 的项目,它知道如何排序.

为了让 ArrayList.Sort 与自定义 class 的实例一起工作,它的项目需要实现 IComparable 接口,System.Int32 就是这种情况(即 VBA 中的 Long)、System.String 和所有其他原始 .NET 类型,我 认为 VBA 原始类型确实会通过 .NET 互操作正确封送 - 但不是自定义 classes.

尝试添加对mscorlib.tlb的引用,然后在defaultPropclass模块中指定这个(你不能实现在后期绑定库中定义的接口):

Implements IComparable

然后实现界面 - 应该看起来像这样(使用代码面板下拉菜单确保获得正确的签名 - 不要只是复制粘贴这个片段:

Private Function IComparable_CompareTo(ByVal obj As Variant) As Long
    Dim other As defaultProp
    Set other = obj
    ' return Less than zero (-1) if this object 
    ' is less than the object specified by the CompareTo method.

    ' return Zero (0) if this object is equal to the object 
    ' specified by the CompareTo method.

    ' return Greater than zero (1) if this object is greater than 
    ' the object specified by the CompareTo method.
End Function

既然您的自定义 class 实现了接口 ArrayList.Sort 用来确定您的 defaultProp 项目如何相互关联,我看不出它失败的原因。

IMO,你是在滥用跨越界限的东西。您正在使用 VBA 的默认属性(我通常认为这是一种不好的做法),然后您正在使用 .NET 的 ArrayList 并尝试 Sort 它。

我认为看看是否可以在 VBA class 上实现 IComparable 然后让 ArrayList 使用 [=12] 会更合乎逻辑=] 接口来比较一个对象与其他对象,但你希望它进行比较,而不使用任何 hacked 的默认属性。