我需要在VBA中创建一个新的类,它可以支持一些基本的数学操作(加、乘等)。在VBA中不允许操作符重载,因此,为此,我考虑创建以下接口
INumeric
Public Function Add(ByVal other As INumeric) As INumeric
End Function
Public Function Multiply(ByVal other As INumeric) As INumeric
End Function
Public Function Negative() As INumeric
End Function
'[...] etc它定义了对我想使用的所有操作符(+、-、^、%等)的响应。也许每个接口都有一个单独的接口,或者一个鸭子类型的松散接口(即,只需定义一个.Add方法像蟒蛇一样,而不是Implements)。
这可与数学课结合使用,以取代运算符的功能:
Maths
Option Explicit
'@PredeclaredID
Public Function Add(ByVal first As Variant, ByVal second As Variant) As Variant
If TypeOf first Is INumeric Then
On Error GoTo defaultAdd
Dim numericFirst As INumeric
Set numericFirst = first
Set Add = numericFirst.Add(second)
ElseIf TypeOf second Is INumeric Then
On Error GoTo defaultAdd
Dim numericSecond As INumeric
Set numericSecond = second
Set Add = numericSecond.Add(first)
Else
defaultAdd:
On Error GoTo -1
On Error GoTo errHandle
Add = first + second
End If
Exit Function
errHandle:
err.Description = "Arguments couldn't be added :( try implementing INumeric"
err.Raise 5
End Function
Public Function Negate(ByVal value As Variant) As Variant
'Similar sort of stuff
End Function
'[...] etc然后在我的代码里
Dim result As Variant
Set result = Maths.Add(INumeric1, INumeric2) 'returns INumeric probably
result = Maths.Add(IsNumeric1, IsNumeric2) 'returns IsNumeric probably其中IsNumeric1只表示定义了+运算符的值-例如Long或Double (甚至是String__;"3“+ "4”= "34“ofc!)
正如您所看到的,这变得非常快,特别是如果我想实现10+操作符的话。就这一点而言,VBA Math库的其余部分--我目前的方法似乎很冗长,而且并不特别枯燥。
,所以我想知道是否有什么库可以添加到我的VBA项目中,它定义了类似于这些接口的接口,并将它们用于数学或逻辑方程中?或者说有点不同,并避免了一个X问题;,我如何能够创建自定义数据类型,可以直接用于一般的数学表达式?,我可以想象创建类来定义它们对操作的响应,但我对其他方法开放。
附录
FWIW,我创建了一个示例实现类(还为Create ( the;)方法预先声明)。它代表了一种科学的测量方法,它具有价值和不确定性。
Option Explicit
'@PredeclaredID
Implements INumeric
Public value As Double
Private uncertainty As Double
Public Function Take(ByVal apparentValue As Double, Optional ByVal absErr As Double = 0, Optional ByVal relErr As Double = 0) As Measurement
With New Measurement
.value = apparentValue
If absErr <> 0 Then
.absoluteErr = absErr
ElseIf relErr <> 0 Then
.relativeErr = relErr
Else
'must be a perfect number, no errors
.absoluteErr = 0 'default value so no point
End If
Set Take = .Self
End With
End Function
Public Property Get relativeErr() As Double
relativeErr = Abs(uncertainty / value)
End Property
Public Property Let relativeErr(ByVal relErr As Double)
uncertainty = relErr * value
End Property
Public Property Get absoluteErr() As Double
absoluteErr = Abs(uncertainty)
End Property
Public Property Let absoluteErr(ByVal absErr As Double)
uncertainty = absErr
End Property
Public Property Get Self() As Measurement
Set Self = Me
End Property
Public Function toString(Optional ByVal formatWithRelErr As Boolean = True) As String
If formatWithRelErr Then
toString = value & "±" & Me.relativeErr * 100 & "%"
Else
toString = value & "±" & Me.absoluteErr
End If
End Function
Private Function INumeric_Add(ByVal other As Variant) As INumeric
If TypeOf other Is Measurement Then
Set INumeric_Add = Measurement.Take(Me.value + other.value, absErr:=Me.absoluteErr + other.absoluteErr)
Else
Set INumeric_Add = Maths.Add(Me, Measurement.Take(other))
'or Set INumeric_Add = Measurement.Take(Me.value + other, absErr:=Me.absoluteErr)
End If
End Function
Private Function INumeric_Multiply(ByVal other As Variant) As INumeric
If TypeOf other Is Measurement Then
Set INumeric_Multiply = Measurement.Take(Me.value * other.value, relErr:=Me.relativeErr + other.relativeErr)
Else
Set INumeric_Multiply = Maths.Multiply(Me, Measurement.Take(other))
End If
End Function
Private Function INumeric_Negative() As INumeric
Set INumeric_Negative = Measurement.Take(-Me.value, absErr:=Me.absoluteErr)
End Function并且可以用这个来测试
Sub test()
Dim a As Measurement, b As Measurement, c As Integer
Set a = Measurement.Take(10, absErr:=1)
Set b = Measurement.Take(15, relErr:=0.2)
c = 3 'treated equiv to Measurement.Take(3, relErr = 0)
Debug.Print "a = "; a.toString; " = "; a.toString(False)
Debug.Print "b = "; b.toString; " = "; b.toString(False)
Debug.Print "c ="; c
Dim aPlusB As Measurement
Set aPlusB = Maths.Add(a, b)
Debug.Print "a + b = "; aPlusB.toString
Dim bPlusC As Measurement
Set bPlusC = Maths.Add(c, b)
Debug.Print "b + c = "; bPlusC.toString(formatWithRelErr:=False)
Debug.Print "3.2 + 7.3 ="; Maths.Add(3.2, 7.3)
On Error Resume Next
Debug.Print Maths.Add("k", 4)
If err.Number <> 0 Then Debug.Print "Err:"; err.Number; "- "; err.Description
End Sub它输出这个
a = 10±10% = 10±1
b = 15±20% = 15±3
c = 3
a + b = 25±16%
b + c = 18±3
3.2 + 7.3 = 10.5
Err: 5 - Arguments couldn't be added :( try implementing INumeric发布于 2019-03-29 10:59:36
不确定我是否在同一页面上,但您可以在clsMaths中按照以下思路做一些事情
Private colNumbersForOperation As Collection
Public Enum enmOperations
enmSum = 1
enmMult = 2
enmDivide = 3
End Enum
Private Sub class_initialize()
Set colNumbersForOperation = New Collection
End Sub
Public Function Load_Number_To_Collection(varEntry As Variant) As Collection
Dim c As Excel.Range
If TypeOf varEntry Is Excel.Range Then
For Each c In varEntry.Cells
colNumbersForOperation.Add c.Value
Next c
Else
colNumbersForOperation.Add varEntry
End If
End Function
Public Function OperateOnNumbers(enmOperation As enmOperations) As Double
Dim v As Variant
For Each v In colNumbersForOperation
Select Case enmOperation
Case enmSum
OperateOnNumbers = OperateOnNumbers + v
Case enmMult
OperateOnNumbers = IIf(OperateOnNumbers = 0, v, OperateOnNumbers * v)
Case enmDivide
OperateOnNumbers = IIf(OperateOnNumbers = 0, v, OperateOnNumbers / v)
Case Else
End Select
Next v
End Function这可以像这样使用
Dim c As New clsMaths
c.Load_Number_To_Collection 10
c.Load_Number_To_Collection 20
c.Load_Number_To_Collection Range("a1:a10")
Debug.Print c.OperateOnNumbers(enmSum)
Debug.Print c.OperateOnNumbers(enmMult)
Debug.Print c.OperateOnNumbers(enmDivide)https://stackoverflow.com/questions/55415216
复制相似问题