默认排序类组属性
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 回合,而不是它的值(通过添加 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 使用的那样笨拙?任何关于尝试更多内置排序算法的建议也会很有用!
如果您将 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.DefaultValue
或 arr.Add (v)
- 然后你的 ArrayList
将包含类型 Single
的项目,它知道如何排序.
为了让 ArrayList.Sort
与自定义 class 的实例一起工作,它的项目需要实现 IComparable
接口,System.Int32
就是这种情况(即 VBA 中的 Long
)、System.String
和所有其他原始 .NET 类型,我 认为 VBA 原始类型确实会通过 .NET 互操作正确封送 - 但不是自定义 classes.
尝试添加对mscorlib.tlb的引用,然后在defaultProp
class模块中指定这个(你不能实现在后期绑定库中定义的接口):
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 的默认属性。
长话短说:
有什么方法可以将 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 回合,而不是它的值(通过添加 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 使用的那样笨拙?任何关于尝试更多内置排序算法的建议也会很有用!
如果您将 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.DefaultValue
或 arr.Add (v)
- 然后你的 ArrayList
将包含类型 Single
的项目,它知道如何排序.
为了让 ArrayList.Sort
与自定义 class 的实例一起工作,它的项目需要实现 IComparable
接口,System.Int32
就是这种情况(即 VBA 中的 Long
)、System.String
和所有其他原始 .NET 类型,我 认为 VBA 原始类型确实会通过 .NET 互操作正确封送 - 但不是自定义 classes.
尝试添加对mscorlib.tlb的引用,然后在defaultProp
class模块中指定这个(你不能实现在后期绑定库中定义的接口):
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 的默认属性。