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


Я пытаюсь избежать струны передаются по как допустимое значение. Возможность ошибиться-это слишком высокая на мой вкус, и решение, которое я придумал-это использовать Enum. Это обеспечивает преимущество IntelliSense при попытке использовать значения. Похожие на вводе sheet1.Visible = что дает допустимые параметры листе собственность с его типом объявлен As SimpleSpanBracing позволяет допустимые значения будут выбраны. Теперь, когда мне нужно использовать что-то или Get или Let значение я используйте конвертер, чтобы убедиться, что я не собираюсь ошибочно перепутать корпуса, ends only или midspanи случайно получить ложно-положительный/отрицательный.

Есть ли что-нибудь, что я упускаю или не предотвращать?

Перечисление с допустимыми параметрами. notSet вариант, потому что я не хочу предполагать по умолчанию. Я бы предпочел, чтобы выяснить, что вызывает проблему и как это произошло.

Public Enum SimpleSpanBracing
    notSet
    endsonly
    midspan
    thirdspan
End Enum

SpanBracingConverter класс, который делает фактическое преобразование. Я не озабочены тем, чтобы значение не было установлено, но установка его на недопустимый вопросов приведет к ошибке, чтобы быть поднят, во избежание ложно-положительных/отрицательных, упомянутых выше.

Private Const spanEnd As String = "ENDS ONLY"
Private Const spanMid As String = "MIDSPAN"
Private Const spanThird As String = "1/3 SPAN"
Private Const INVALID_INPUT As Long = 5

Public Function ToString(ByVal value As SimpleSpanBracing) As String
    If value = endsonly Then
        ToString = spanEnd
    ElseIf value = midspan Then
        ToString = spanMid
    ElseIf value = thirdspan Then
        ToString = spanThird
    Else
        Err.Raise INVALID_INPUT, "SpanBracingConverter.ToString()", "Invalid input supplied"
    End If
End Function
Public Function ToEnum(ByVal value As String) As SimpleSpanBracing
    value = UCase$(value)
    If value = spanEnd Then
        ToEnum = endsonly
    ElseIf value = spanMid Then
        ToEnum = midspan
    ElseIf value = spanThird Then
        ToEnum = thirdspan
    Else
        Err.Raise INVALID_INPUT, "SpanBracingConverter.ToEnum()", "Invalid input supplied"
    End If
End Function
Public Function ValidateString(ByVal value As String) As String
    ValidateString = ToString(ToEnum(value))
End Function

Ниже представлены модульные тесты, которые я создал с Rubberduck , чтобы проверить этот конвертер.

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

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

    'Act:
    Dim lowerEnd As SimpleSpanBracing
    lowerEnd = sut.ToEnum("ends only")
    Dim upperEnd As SimpleSpanBracing
    upperEnd = sut.ToEnum("ENDS ONLY")
    Dim lowerMid As SimpleSpanBracing
    lowerMid = sut.ToEnum("midspan")
    Dim upperMid As SimpleSpanBracing
    upperMid = sut.ToEnum("MIDSPAN")
    Dim lowerThird As SimpleSpanBracing
    lowerThird = sut.ToEnum("1/3 span")
    Dim upperThird As SimpleSpanBracing
    upperThird = sut.ToEnum("1/3 SPAN")

    Dim endInput As String
    endInput = sut.ToString(endsonly)
    Dim midInput As String
    midInput = sut.ToString(midspan)
    Dim thirdInput As String
    thirdInput = sut.ToString(thirdspan)

    'Assert:
    Assert.areequal SimpleSpanBracing.endsonly, lowerEnd
    Assert.areequal SimpleSpanBracing.endsonly, upperEnd
    Assert.areequal SimpleSpanBracing.midspan, lowerMid
    Assert.areequal SimpleSpanBracing.midspan, upperMid
    Assert.areequal SimpleSpanBracing.thirdspan, lowerThird
    Assert.areequal SimpleSpanBracing.thirdspan, upperThird

    Assert.areequal "ENDS ONLY", endInput
    Assert.areequal "MIDSPAN", midInput
    Assert.areequal "1/3 SPAN", thirdInput

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

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

    'Arrange:

    'Act:
    With New SpanBracingConverter
        .ToEnum "fail"
    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 UnsetEnumValue()
    Const ExpectedError As Long = 5
    On Error GoTo TestFail

    'Arrange:

    'Act:
    With New SpanBracingConverter
        .ToString SimpleSpanBracing.notSet
    End With

TestExit:
    Exit Sub
TestFail:
    If Err.Number = ExpectedError Then
        Resume TestExit
    Else
        Assert.Fail "Expected error was not raised."
    End If
End Sub

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

    'Arrange:

    'Act:
    With New SpanBracingConverter
        .ToString 4
    End With

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

TestExit:
    Exit Sub
TestFail:
    If Err.Number = ExpectedError Then
        Resume TestExit
    Else
        Assert.Fail "Expected error was not raised."
    End If
End Sub

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

    'Arrange:

    'Act:

    'Assert:
    With New SpanBracingConverter
        Assert.areequal "ENDS ONLY", .ValidateString("ENDS ONLY")
        Assert.areequal "ENDS ONLY", .ValidateString("ends only")
        Assert.areequal "MIDSPAN", .ValidateString("MIDSPAN")
        Assert.areequal "MIDSPAN", .ValidateString("midspan")
        Assert.areequal "1/3 SPAN", .ValidateString("1/3 SPAN")
        Assert.areequal "1/3 SPAN", .ValidateString("1/3 span")
    End With

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


Редактировать: мой последующий вопрос, Часть 2 продолжает свою работу на преобразователь класса.



228
7
задан 2 апреля 2018 в 10:04 Источник Поделиться
Комментарии
1 ответ

Перечисление

В Enum Это по сути тип, он имеет члены. Члены должны быть PascalCase - Я изменить alllowercase корпус для соблюдения этой конвенции:

Public Enum SimpleSpanBracing
NotSet = 0
EndsOnly
MidSpan
ThirdSpan
End Enum

Я бы также сделать NotSet значение явно 0, потому что иначе кто-то может очень хорошо думаю, что перечисление будет выглядеть красивее, если все ее члены были в алфавитном порядке, и что бы по-царски натворить.


Конвертер

Дело, что класс по сути получить карту строк для перечисления значений, и enum значения в строки. Всякий раз, когда я использую слово "карта", я автоматически думаю о Dictionary.

Изображение вашего перечисления в 200 человек. Я сомневаюсь, что вы обнаружите, что If...ElseIf...ElseIf... условная структура красиво и аккуратно, да?

А Select Case...Case...Case... блок бы лучше, ИМО, но все равно неприятно поддерживать, поскольку вы, по сути, нужны те же блоки в два раза.

Я бы пошел с Private Dictionary кузова со строками и ценится с перечисления.

Тогда я бы еще Private DictionaryС ключом с [строковое представление] перечислимые значения, и оценивается с соответствующих строк.

В классе' Initialize обработчик, я бы заселить один из них, а затем перебрать его, чтобы автоматически заполнить остальные; конечно, эти два метода будут осуществляться в собственную Private Sub процедур, а строковые константы не будет больше служить какой-то цели.

Затем, ToString и ToEnum будет в конечном итоге так просто, как он получает:

Public Function ToString(ByVal value As SimpleSpanBracing) As String
If Not StringForEnum.Exists(CStr(value)) Then
ThrowInvalidArgument "ToString", CStr(value)
'Exit Function
End If
ToString = StringForEnum(CStr(value))
End Function

Public Function ToEnum(ByVal value As String) As SimpleSpanBracing
If Not EnumForString.Exists(value) Then
ThrowInvalidArgument "ToEnum", value
'Exit Function
End If
ToEnum = EnumForString(value)
End Function

Я бы выделенное ThrowInvalidArgument процедура отвечает за бросание недопустимый аргумент ошибка, и переместить INVALID_INPUT декларация есть... или просто удалить его и текст сообщения строку.

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

Цель ValidateString не кажется мне супер-очевидно, просто по имени; мой мозг как-то ожидает "ValidateFoo" либо вернуть Boolean говорит мне, все ли указано допустимое Fooили выдавать сообщение об ошибке, учитывая недопустимое значение. Этот метод на самом деле просто "туда-обратно" функцию полезности, которая, ИМО, должна быть подставлена в места вызова.

В качестве бонуса использовать этот словарь подход, вы могли бы выставить Property Get член, которая возвращает массив, содержащий все допустимые значения перечислений, и другая, которая возвращает всех допустимых строк. Подробнее об этом через минуту.


Тесты

ИМО все Dim заявления захламление "акт" часть тесты и делая это тяжелее, чем нужно, чтобы прочитать сам "и. о." исполняемых операторов.

Rubberduck по IAssert интерфейс предоставляет удобный SequenceEquals метод, который можно использовать для перебора и сравнения элементов массива; вместо того, чтобы делать серию Assert.AreEqual звонки, вы могли бы конвертере выставить Property Get члена, что дает вам всех допустимых строк, как массив, Property Get члена, что дает все допустимые значения перечисления в другой массив, а затем перебрать массив для заполнения "результат" массив, вызывая ваше СУТ/преобразование в одном месте (в этом цикле) - а потом сделать один Assert называть и сравнивать ожидаемые и фактические результирующий массив.

3
ответ дан 4 апреля 2018 в 06:04 Источник Поделиться