How to keep all hardcoded class values ​​in one place

I have created a class in VBA that would like to have some preset values ​​associated with it. I'm new to classes and wondering what is the best (/ good) way to structure my VBA code inside a class object so that I can easily access these defaults as I type. The answer should preferably:

  • Require relatively few extra lines of code on top of the lines that I believe would be required to actually hard-code the values
    • i.e. something like extra Sub

      for each hardcoded value would not be ideal
    • This means my class won't get too cluttered.
  • Let me use intellisense somehow to access these hardcoded values.

It's worth noting that my main use for these hardcoded values ​​is to set default values ​​for my class variables (by looping in an event initialize

), but I can also access them in other parts of the code

What I have tried:

Declaration Enum

to keep my hardcoded values

'Declarations
Private Enum startingVals
    Top = 10
    Column_Count = 4
    Left = 15
    ...
End Enum
Private topVal As Long 'variables which I assign default values to
Private colCnt As Long
Private leftVal As Long

Private Sub Class_Initialize()
topVal = startingVals.Top
colCnt = startingVals.Column_Count
'etc.
End Sub

      

This has 2 limitations;

  • Enumerations can only store Long

    s
    • Work around this by using a load Const

      instead, but then you have to remember every persistent name, plus it looks cluttered in your code
  • Although I am getting Intellisense for .Top

    and .Column_Count

    , I still need to enter startVals completely
    • This is significantly better than memorizing all the hard-coded constant names, but

Ideally I could do this

Private Sub Class_Initialize()
With startingVals 'or Dim v As startingVals, With v
    topVal = .Top
    colCnt = .Column_Count
    'etc.
End With
End Sub

      

But I can not


Another approach would be to use a function to store values, so that you could only declare different types as long.

'Declarations
Private Enum startingVals
    Top = 1
    Column_Count = 2
    Left = 3
    ...
End Enum
Private topVal As Long 'variables which I assign default values to
Private colCnt As Long
Private leftVal As Long

Private Sub Class_Initialize()
topVal = getval(Top)
colCnt = getval(Column_Count)
'etc.
End Sub

      

Then, to access your hardcoded data, you have a function that takes enum input (allows intellisense)

Private Function getval(dataType As startVals) As String
Const savedData As String = "1,2,1.17171717,hey,me,you" 'save the return values for the index specified by dataType
getval = Split(savedData, ",")(dataType) 'use datatype as a direct index of the array
End Function

      

or another way to store values

Private Function getval(dataType As startVals) As String
Const colV As Long = 10 'index 1
Const topV As String = "This is the top" 'index 2
'...
If dataType = ColumnCount Then getval = colV 'use dataType to check what to return
If dataType = Top Then getval = colV 'could use a select case too
'etc
End Function

      

  • But in any case, we still cannot access the constants if we do not enter the function name.
  • Also this approach requires me to update the enum declaration in my class declaration part and the const declaration inside the function itself, making it difficult to work with the code.

TL; DR

What's the best way to store hardcoded values ​​in a class object where it is best stated

  • Uses VBA intellisense (autocomplete) so I can quickly select the value I want as I type
  • Is neat, self contained and concise in my class module to avoid clutter
  • Can contain any hardcoded value type (datatype) (although I only use it Long

    in the project I'm currently working on)
  • Can be accessed without having to enter the initialization part every time (like name function

    or Enum

    )
    • Of course, the block or function equivalent With

      would be accurate, as it only requires one instance of specifying the enum / data collection name
+3


source to share


3 answers


... so my class doesn't get messed up

I would decouple the class from the initialization process by adding another class by calling it Initializer

. The initializer will know how to initialize my objects, contain the default values, and fill my object with those default values. But in the initializer you will have to write tasks, without intellisense magic, but just write m_

and select from the list. NTN

Foo class

Option Explicit

'variables which I assign default values to
Private m_topVal As Long
Private m_colCnt As Long
'Private m_leftVal As Long

Private Sub Class_Initialize()
    Dim initializer As FooInitializer
    Set initializer = New FooInitializer
    initializer.Initialize Me
End Sub

Public Property Get TopVal() As Long
    TopVal = m_topVal
End Property

Public Property Let TopVal(ByVal vNewValue As Long)
    m_topVal = vNewValue
End Property

Public Property Get ColCnt() As Long
    ColCnt = m_colCnt
End Property

Public Property Let ColCnt(ByVal vNewValue As Long)
    m_colCnt = vNewValue
End Property

' Add Get/Let(Set) for other member variables as well

      



FooInitializer class

Option Explicit

' Default startingVals values
Private m_topValDefault As Integer
Private m_columnCountDefault As Integer
'etc.

Public Sub Initialize(ByRef fooInstance As Foo)
    fooInstance.TopVal = m_topValDefault
    fooInstance.ColCnt = m_columnCountDefault
    'etc.
End Sub

Private Sub Class_Initialize()
    m_topValDefault = 10
    m_columnCountDefault = 4
    'etc.
End Sub

      

Standard module

Option Explicit

Sub test()
    Dim f As Foo
    Set f = New Foo
    ' f is now initizlized via initializer with default values
    Debug.Print f.TopVal
    Debug.Print f.ColCnt
End Sub

      

+2


source


You can use constants to define default values ​​in one place.

Then you can easily access them with Ctrl + Space + Default ...



Const Default_Top = 10
Const Default_Text = "abcd"

Private m_topVal As Long
Private m_text As String

Private Sub Class_Initialize()
  m_topVal = Default_Top
  m_text = Default_Text
End Sub

Public Property Get TopVal() As Long
  TopVal = m_topVal
End Property

      

+2


source


I can't claim ownership of this solution, but when I ran into it over Code Review it was ingenious enough for me to include it in quite a lot of my code since then.

As used in some other object-oriented languages, accessing the internal variables of a class instance using a construct is this

very familiar. The concept is expanded in VBA using an example here.

I created a class module named CustomClass

and inside it a private custom type is created for use only within that class.

Option Explicit

Private Type CustomType
    Top As Long
    Name As String
    Temperature As Double
    anotherCustomObject As CustomClass
End Type
Private this As CustomType

      

By working this way, you can create any number of internal variables of any combination of types (including objects). Accessing and initializing each of these values ​​is now as easy as using a structured variable this

. The tab Class_Initialize

shows how:

Private Sub Class_Initialize()
    this.Top = 150
    this.Name = "Wayne"
    this.Temperature = 98.6
    Set this.anotherCustomObject = New CustomClass
End Sub

      

Set and initialize all your values ​​in your heart content.

Alternatively, you can set each one with property accessories if you like. Some of them may be read-only:

'--- Read Only Properties
Public Property Get Name() As String
    Name = this.Name
End Property

Public Property Get Temperature() As Double
    Temperature = this.Temperature
End Property

Public Property Get ContainedObject() As CustomClass
    Set ContainedObject = this.anotherCustomObject
End Property

      

And you can create some that read / write:

'--- Read/Write Properties
Public Property Let Top(ByVal newValue As Long)
    this.Top = newValue
End Property

Public Property Get Top() As Long
    Top = this.Top
End Property

      

Also, you can still easily use properties in the class using the keyword Me

:

'--- Internal Private Methods
Private Sub TestThisClass()
    Debug.Print "current temperature is " & Me.Temperature
    Debug.Print "the Top value is " & Me.Top
End Sub

      

Of course, all this works when you declare an object CustomClass

in another module.

Hope this helps you a little to help you organize your code.

(For convenience, here's the whole class :)

Option Explicit

Private Type CustomType
    Top As Long
    Name As String
    Temperature As Double
    anotherCustomObject As CustomClass
End Type
Private this As CustomType

Private Sub Class_Initialize()
    this.Top = 150
    this.Name = "Wayne"
    this.Temperature = 98.6
    Set this.anotherCustomObject = New CustomClass
End Sub

'--- Read Only Properties
Public Property Get Name() As String
    Name = this.Name
End Property

Public Property Get Temperature() As Double
    Temperature = this.Temperature
End Property

Public Property Get ContainedObject() As CustomClass
    Set ContainedObject = this.anotherCustomObject
End Property

'--- Read/Write Properties
Public Property Let Top(ByVal newValue As Long)
    this.Top = newValue
End Property

Public Property Get Top() As Long
    Top = this.Top
End Property

'--- Internal Private Methods
Private Sub TestThisClass()
    Debug.Print "current temperature is " & Me.Temperature
    Debug.Print "the Top value is " & Me.Top
End Sub

      

0


source







All Articles