如何在一个地方保存所有类硬编码值

时间:2017-07-31 18:35:57

标签: vba excel-vba class enums intellisense

我在VBA中创建了一个类,我想要一些与之关联的预设值。我是新手,我想知道在类对象中构造我的VBA代码的最好(/一个好)方法是什么,这样我可以在输入时轻松访问这些默认值。答案最好:

  • 除了我认为实际硬编码所需的行之外,需要相对较少的额外代码行
    • 即。类似于每个硬编码值的附加Sub并不理想
    • 这是为了防止我的班级变得太杂乱
  • 允许我以某种方式使用intellisense来访问这些硬编码值

值得注意的是,我对这些硬编码值的主要用途是将默认值设置为我的类的变量(通过在initialize事件中循环),但我可能还想在其他部分访问它们代码

我尝试了什么:

声明Enum以保存我的硬编码值

'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

这有两个限制;

  • 枚举只能存储Long
    • 使用Const s加载来解决这个问题,但是你必须记住每个常量的名称,加上它看起来很混乱
  • 虽然我获得了.Top.Column_Count的智能感知,但仍然需要完整输入startingVals
    • 这比通过
    • 记住所有硬编码的常量名称要好得多

理想情况下,我可以这样做

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

但我不能

另一种方法是使用函数来保存值,这样就可以将不同的类型声明为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

然后要访问硬编码数据,你有一个带枚举输入的函数(允许智能感知)

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

或其他保存值的方法

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
  • 但是除非我们输入函数名称,否则我们仍然无法访问常量。
  • 这种方法也要求我更新我的类声明部分的枚举声明和函数本身的const声明,使代码更难维护。

TL; DR

在类对象中保存硬编码值的最佳方法是什么,其中最佳定义为

  • 使用VBA intellisense(自动填充),这样我就可以在输入时快速选择我想要的值
  • 在我的班级模块中,整洁,自包含和简洁,以避免混乱
  • 最好能保留任何类型(数据类型)的硬编码值(虽然我只在我目前正在进行的项目中使用Long
  • 无需每次都输入初始化部分(例如functionenum名称)即可访问
    • 当然,With块或函数等效就好了,因为只需要指定枚举/数据集合名称的一个实例

3 个答案:

答案 0 :(得分:2)

您可以使用常量在一个位置定义默认值。

然后,您可以使用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

答案 1 :(得分:2)

  

...以防止我的班级变得太杂乱

我将该类与其初始化过程分开,添加另一个类可以调用它Initializer。初始化程序将知道如何初始化我的对象,将包含默认值,并将使用此默认值填充我的对象。但是在初始化程序中,你必须编写赋值,没有魔法智能感知,只需简单地写m_并从列表中选择。 HTH

  

Class Foo

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
  

Class FooInitializer

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
  

标准模块

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 :(得分:0)

我不能声称对此解决方案拥有所有权,但当我在Code Review上遇到它时,我的天才足以将其合并到我的很多代码中。

在其他一些面向对象语言中使用时,使用this构造访问类内部实例变量非常熟悉。使用此处的示例将该概念扩展到VBA。

我创建了一个名为CustomClass的类模块,并在其中创建了一个私有自定义类型,仅供该类使用。

Option Explicit

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

以这种方式工作,您可以创建任意类型组合(包括对象)的任意数量的内部变量。现在,访问和初始化每个值都与使用this结构化变量一样简单。 Class_Initialize子显示如何:

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

另外,您仍然可以使用Me关键字在课堂上轻松使用这些属性:

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

当然,当你在不同的模块中声明CustomClass的对象时,这一切都有效。

希望这有助于帮助规范您的代码。

(为方便起见,全班同学:)

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