vba - 按默认属性对一组类进行排序

标签 vba excel class sorting icomparable

TL;博士:

有没有办法将类集合/列表传递给库排序算法,并让它返回排序列表(最好通过命名/默认类属性)?

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

在 VBA 中,我已经成功模仿了一半。通过设置类'default member Attribute ,您可以直接在类上使用比较运算符( <=>= 等)。以示例类为例:

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

可以比较此类的两个实例:
 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 排序算法,那么按默认值对类进行排序应该没有问题*。但是我更喜欢使用内置/库排序算法(出于同样的原因,任何人都会这样做;清晰度、效率、正确的错误处理等)

*these algorithms 之一将为此工作,尽管必须修改以切换整个类轮次,而不是它的值(通过添加 Set s)

由于 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 使用的那样笨拙吗?任何有关尝试更多内置排序算法的建议也会很有用!

最佳答案

这与 VBA 比较运算符无关,ArrayList是一个 .NET 类,因此当您使用它时,您就置身于 .NET 世界。

arr.Add v 'no problem here

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

为了 ArrayList.Sort要使用自定义类的实例,它的项目需要实现 IComparable接口(interface),System.Int32 就是这种情况(即 Long 在 VBA 中),System.String和所有其他原始 .NET 类型,我认为 VBA 原始类型确实可以通过 .NET 互操作正确编码 - 但不是自定义类。

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

然后实现接口(interface) - 应该看起来像这样(使用代码 Pane 下拉菜单确保获得正确的签名 - 不要只是复制粘贴此片段 :
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

现在您的自定义类实现了接口(interface) ArrayList.Sort用于确定您的 defaultProp项目彼此相关,我看不出它失败的原因。

关于vba - 按默认属性对一组类进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47775959/

相关文章:

Javascript 作用域和闭包,变量保持其值

python - 有没有办法在Python中进入类命名空间?

vba - 标准 SUMIFS 公式内的用户定义函数

vba - 如何使用查找和替换在 VBA 编辑器中找到带有新行的单词?

excel - 控制行标题的双击事件

excel - 我需要在 Excel 工作表中获取 2 列,并将它们转换为以第 1 列作为标题的数据范围

vba - 添加 'Excel sheet updated'消息框

c++ - 指向具有自定义结构的指针的指针

vba - 在保存事件之前,需要帮助同时循环两个单元格

sql - 'Incdntno.Value'处 undefined variable