Можно ли позволить и получить с различными типами данных в VBA? - PullRequest
1 голос
/ 31 мая 2019

В настоящее время я работаю над надстройкой Excel VBA для обработки экспорта CSV из одной системы в формат, который заинтересованные стороны хотели бы просмотреть. Я довольно плохо знаком с ООП, но подумал, что это возможно преобразовать типы приоритетов в коде Let и хранить данные в том же формате, в котором они будут выводиться.

Я написал следующий класс:

'Class Module "Project"
Option Explicit

Private m_sPriority As String

Property Let Priority(lInput As Long)
    Select Case lInput
        Case 1
            m_sPriority = "High"
        Case 2
            m_sPriority = "Medium"
        Case 3
            m_sPriority = "Low"
        Case Else
            m_sPriority = "No Priority"
    End Select
End Property

Property Get Priority() As String
    Priority = m_sPriority
End Property

И это модуль для проверки:

'Standard Module
Option Explicit

Sub test()
        Dim Project As Project
        Set Project = New Project

        Project.Priority = 1
        Debug.Print Project.Priority
End Sub

Я ожидаю увидеть вывод «High» на консоль при запуске этого.

Есть ли способ сделать это в VBA или, альтернативно, мой код искажен?

1 Ответ

7 голосов
/ 31 мая 2019

Да, ваш код поврежден.Что бы это ни стоило, вы не можете сделать это и в .NET - синтаксис делает его довольно однозначным, будь то в C #:

private string _priority;
public string Priority 
{
    get { return _priority; }
    private set { _priority = value; }
}

... или в VB:

Private _priority As String
Public Property Priority() As String
    Get
        Return _priority
    End Get
    Private Set(ByVal value As String)
        _priority = value
    End Set
End Property

Свойство может быть Long или String, оно не может быть и тем и другим.Get / Let / Set методы доступа должны быть согласованными, также в VBA.

Вы можете обмануть , потеряв безопасность типов и раннее связывание,сделав вашу собственность Variant ... но это не совсем хороший способ начать работу с ООП; -)

Public Enum PriorityLevel
    NoPriority = 0
    HighPriority
    MediumPriority
    LowPriority
End Enum

Private Type InstanceState
    Priority As PriorityLevel
    '...
End Type

Private this As InstanceState

Public Property Get Priority() As Variant
    Priority = PriorityName(this.Priority)
End Property

Public Property Let Priority(ByVal value As Variant)
    this.Priority = value
End Property

Private Function PriorityName(ByVal value As PriorityLevel) As String
    Select Case value
        Case HighPriority
            PriorityName = "High"
        Case MediumPriority
            PriorityName = "Medium"
        Case LowPriority
            PriorityName= "Low"
        Case Else
            PriorityName= "Undefined"
    End Select
End Function

Хотя это работает идеально и выглядит довольно аккуратно на поверхности, потребляя этокласс, когда вы не написали, это определенно будет удивительно: если вы установите (Let) a Long, вы по праву ожидаете также Get a Long.Этот класс требует наличия свойства PriorityName get-only:

Public Property Get Priority() As PriorityLevel
    Priority = this.Priority
End Property

Public Property Let Priority(ByVal value As PriorityLevel)
    this.Priority = value
End Property

Public Property Get PriorityName() As String
    Select Case this.Priority
        Case HighPriority
            PriorityName = "High"
        Case MediumPriority
            PriorityName = "Medium"
        Case LowPriority
            PriorityName = "Low"
        Case Else
            PriorityName = "Undefined"
    End Select
End Property

Теперь преимущества раннего связывания и безопасности типов (независимо от того, что вы используете в VBA), становятся очевидными: когдавы пишете код, который присваивает свойство Priority объекта этого типа, IntelliSense для типа Enum направляет написание выражения:

available enum members appear in a dropdown list

Более того, Enum - это , абстрагирующее базовое числовое значение, которое становится неактуальным: вместо волшебного жесткого кода 1 код теперь говорит: HighPriority.Кроме того, аксессор Get настолько прост, насколько это возможно, и это очень хорошо: аксессор Get никогда не должен вызывать ошибок, поэтому, чем проще, тем лучше.

Мораль истории: не делайтевзломайте безопасность типов, если вы можете помочь ей, сделайте все возможное, чтобы ваш код был ранним - избегайте Object и Variant, насколько это возможно;приведите Object к известному классу / интерфейсу везде, где вы можете.

Например, предпочтите:

Dim sheet As Worksheet
' Workbook.Worksheets(index) returns Object; casting it to Worksheet
Set sheet = ActiveWorkbook.Worksheets(1)
sheet.Range("A1").Value = 42

Кому:

' "Range("A1").Value" is entirely late-bound. Beware of typos!
ActiveWorkbook.Worksheets(1).Range("A1").Value = 42
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...