Мне нужно создать новый класс в VBA, который может поддерживать некоторые базовые математические операции (Add, Multiply и т. Д.).Перегрузка операторов не разрешена в 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
метод , как это делает python , нет 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, которая определяет интерфейсы, подобные этим, и использует их в математических или логических уравнениях?Или, говоря по-другому, избегайте вопроса XY; Как я могу создавать пользовательские типы данных, которые можно использовать непосредственно в общих математических выражениях? Я мог бы представить создание классов, которые определяют их собственный ответ на операции, но я открыт для других подходов.
Приложение
FWIW, я создал пример класса реализации (также предварительно объявленного для метода Create (Take;)).Он представляет собой научное измерение, которое имеет значение и неопределенность
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