ВБА класс конвертер для устранения строки используются в качестве допустимых значений, часть2


Мой первоначальный вопрос получил ответ, который помог мне пересмотреть мой код. Ниже приведен обновленный код с преобразователем, который имеет еще несколько вариантов.

Эти перечисления членов предваряется ss с номерами не допускаются в качестве исходных символов.

'SectionSetConverter Class
Public Enum SectionSets
    NotSet
    ss14x6
    ss12x8
    ss12x6
    ss10x10
    ss10x8
    ss10x6
    ss8x8
    Aggregate
    FullList
End Enum

'@Folder("Converters")
Option Explicit

Private StringForEnum As Dictionary
Private EnumForString As Dictionary

Private Sub Class_Initialize()
    PopulateDictionaries
End Sub

Private Sub PopulateDictionaries()
    Set EnumForString = New Dictionary
    EnumForString.CompareMode = TextCompare

    EnumForString.Add "14x6", ss14x6
    EnumForString.Add "12x8", ss12x8
    EnumForString.Add "12x6", ss12x6
    EnumForString.Add "10x10", ss10x10
    EnumForString.Add "10x8", ss10x8
    EnumForString.Add "10x6", ss10x6
    EnumForString.Add "8x8", ss8x8
    EnumForString.Add "Aggregate", Aggregate
    EnumForString.Add vbNullString, FullList

    Set StringForEnum = New Dictionary
    EnumForString.CompareMode = TextCompare
    Dim i As Variant
    For Each i In EnumForString.Keys
        StringForEnum.Add EnumForString.Item(i), i
    Next
End Sub

Public Function ToEnum(ByVal value As String) As SectionSets
    value = UCase$(value)

    If Not EnumForString.Exists(value) Then
        ThrowInvalidArgument "ToEnum", value
    End If

    ToEnum = EnumForString(value)
End Function

Public Function ToString(ByVal value As SectionSets)
    If Not StringForEnum.Exists(value) Then
        ThrowInvalidArgument "ToString", CStr(value)
    End If

    ToString = StringForEnum(value)
End Function

Private Sub ThrowInvalidArgument(ByVal source As String, ByVal value As String)
    Err.Raise 5, Information.TypeName(Me) & "." & source, "Invalid input '" & value & "' was supplied."
End Sub

Public Property Get Enums() As Variant
    Enums = EnumForString.Items
End Property

Public Property Get Strings() As Variant
    Strings = EnumForString.Keys
End Property

Примечание: аннотация '@Folder("Converters") помогает организовать все мои конвертеры в "папку" для более удобного просмотра с кодом исследователь RubberduckVBA надстройки.


Следуя советам @MathieuGuindon я создал собственный Dictionary (требует раннего ссылку в программу, зайдя в инструменты>ссылки>среда выполнения сценариев Microsoft) для каждого из значений.

Там сейчас только один список для поддержания. Население словарь и итерации Keys для заполнения второго списка гарантий, что они не рассинхронизируются и будет отражать правильное значение ключа пары (КВП).

Выше выставлены функций ToEnum и ToString преобразовать параметр в нужное значение. Любая неверная информация о причинах ThrowInvalidArgument можно назвать и поднять соответствующую ошибку.

Наконец свойств, которые позволяют проще модульных тестов, которые по совпадению следовать.

'@TestMethod
Public Sub ValidInputs()
    On Error GoTo TestFail

    'Arrange:
    Dim sut As SectionSetConverter
    Set sut = New SectionSetConverter

    Dim converterEnums As Variant
    converterEnums = sut.Enums

    Dim converterStrings As Variant
    converterStrings = sut.Strings

    Dim actualStrings As Variant
    ReDim actualStrings(LBound(converterStrings) To UBound(converterStrings))

    Dim actualEnums As Variant
    ReDim actualEnums(LBound(converterStrings) To UBound(converterStrings))

    'Act:
    Dim i As Long
    For i = LBound(actualStrings) To UBound(actualStrings)
        actualStrings(i) = sut.ToString(converterEnums(i))
    Next

    For i = LBound(actualEnums) To UBound(actualEnums)
        actualEnums(i) = sut.ToEnum(converterStrings(i))
    Next

    'Assert:
    Assert.sequenceequals converterStrings, actualStrings
    Assert.sequenceequals converterEnums, actualEnums

TestExit:
    Exit Sub
TestFail:
    Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub

'@TestMethod
Public Sub UnsetEnumValue()
    Const ExpectedError As Long = 5
    On Error GoTo TestFail

    'Arrange:

    'Act:
    With New SectionSetConverter
        .ToString SectionSets.NotSet
    End With

Assert:
    Assert.Fail "Expected error was not raised."

TestExit:
    Exit Sub
TestFail:
    If Err.Number = ExpectedError Then
        Resume TestExit
    Else
        Resume Assert
    End If
End Sub

'@TestMethod
Public Sub LargestAssignedEnumValue()
    Const ExpectedError As Long = 5
    On Error GoTo TestFail

    'Arrange:

    'Act:
    With New SectionSetConverter
        .ToString 10
    End With

Assert:
    Assert.Fail "Expected error was not raised."

TestExit:
    Exit Sub
TestFail:
    If Err.Number = ExpectedError Then
        Resume TestExit
    Else
        Resume Assert
    End If
End Sub

Ранее тест ValidInputs было неловкое ощущение. Добавление пользователей SectionSet потребовалось бы мне для обновления модульный тест в любое время. Теперь, если участник добавляется соответствующих допустимых значений уже опробованные, благодаря Enums и Strings свойства SectionSetConverter.

Есть ли другие части я могу улучшить? Я думал о создании IConverter класс и каждый конвертер Implements но я не определились о пользе этого время.



124
2
vba
задан 6 апреля 2018 в 09:04 Источник Поделиться
Комментарии
1 ответ

Я бы пошел с постоянным vbTextCompare для вашего CompareMode на ваши объекты, чтобы пользователь мог просто выбрать, если они хотят использовать раннее или позднее связывание.

В основном, я путать о Enum. Когда мы инициализируем мы -

StringForEnum as Dictionary
StringForEnum(1) = 1
StringForEnum(2) = 2
StringForEnum(3) = 3
StringForEnum(4) = 4
StringForEnum(5) = 5
StringForEnum(6) = 6
StringForEnum(7) = 7
StringForEnum(8) = 8
StringForEnum(9) = 9

Enums as Variant
Enums(0) = 1
Enums(1) = 2
Enums(2) = 3
Enums(3) = 4
Enums(4) = 5
Enums(5) = 6
Enums(6) = 7
Enums(7) = 8
Enums(8) = 9

EnumForString as Dictionary
EnumForString(1) = "14x6"
EnumForString(2) = "12x8"
EnumForString(3) = "12x6"
EnumForString(4) = "10x10"
EnumForString(5) = "10x8"
EnumForString(6) = "10x6"
EnumForString(7) = "8x8"
EnumForString(8) = "Aggregate"
EnumForString(9) = ""

Strings as Variant
Strings(0) = "14x6"
Strings(1) = "12x8"
Strings(2) = "12x6"
Strings(3) = "10x10"
Strings(4) = "10x8"
Strings(5) = "10x6"
Strings(6) = "8x8"
Strings(7) = "Aggregate"
Strings(8) = ""

Правильно, но свои свойства Enums и Strings нет Let метод, который означает, что он не может быть изменен во время работы.

Вы также заметите, что ваши варианты начинаются 0 и ваши словари начинаются 1. Так почему же эти дублируются таким образом, что нужен словарь, считая его требуется ссылка?

Так, я не уверен, но я предполагаю, что целое число ссылок, которые вы хотите запустить на 1 вместо 0. Так что все это может быть достигнуто только одним свойством и одной постоянной

Const STRING_VALUES = "14x6,12x8,12x6,10x10,10x8,10x6,8x8,Aggregate,"

Private Strings As Variant

Public Sub Class_Initialize()
Strings = Split(STRING_VALUES, ",")
End Sub

Public Property Get ToString(value As Long)
ToString = Strings(value - 1)
End Property

Я тоже не понимаю, зачем вам нужно выставить свойство, которое возвращает всю переменной массива - разве это Class? Так что вам не нужно хранить его в другом объекте?

Может быть, мне не хватает точки, но все это кажется немного перебор.

1
ответ дан 12 апреля 2018 в 01:04 Источник Поделиться