R. *_*ter 14 vba const constants
我想有一个常量材料的目录,所以我可以使用如下所示的代码:
Dim MyDensity, MySymbol
MyDensity = ALUMINUM.Density
MySymbol = ALUMINUM.Symbol
Run Code Online (Sandbox Code Playgroud)
显然铝的密度和符号预计不会改变所以我希望它们是常数但我喜欢简单的点符号.
我看到了几个选项,但我不喜欢它们.
为每种材料的每个属性制作常量.这似乎太多常数,因为我可能有20个材料,每个都有5个属性.
Const ALUMINUM_DENSITY As Float = 169.34
Const ALUMINUM_SYMBOL As String = "AL"
Run Code Online (Sandbox Code Playgroud)使用所有材质定义枚举并生成返回属性的函数.密度不是很明显,因为它的值是由函数返回的.
Public Enum Material
MAT_ALUMINUM
MAT_COPPER
End Enum
Public Function GetDensity(Mat As Material)
Select Case Mat
Case MAT_ALUMINUM
GetDensity = 164.34
End Select
End Function
Run Code Online (Sandbox Code Playgroud)似乎Const Structs或Const Objects不会解决这个问题,但也许我错了(甚至可能不被允许).有没有更好的办法?
Com*_*ern 12
使VBA等同于"静态类".常规模块可以具有属性,没有任何东西表明它们不能是只读的.我还将密度和符号包装在一个类型中:
'Materials.bas
Public Type Material
Density As Double
Symbol As String
End Type
Public Property Get Aluminum() As Material
Dim output As Material
output.Density = 169.34
output.Symbol = "AL"
Aluminum = output
End Property
Public Property Get Iron() As Material
'... etc
End Property
Run Code Online (Sandbox Code Playgroud)
这非常接近您期望的使用语义:
Private Sub Example()
Debug.Print Materials.Aluminum.Density
Debug.Print Materials.Aluminum.Symbol
End Sub
Run Code Online (Sandbox Code Playgroud)
如果你在同一个项目中,你甚至可以删除显式Materials限定符(虽然我建议明确它):
Private Sub Example()
Debug.Print Aluminum.Density
Debug.Print Aluminum.Symbol
End Sub
Run Code Online (Sandbox Code Playgroud)
IMO @Comintern击中头部; 这个答案只是另一种可能的选择.
为它创建一个界面.添加一个类模块,调用它IMaterial; 该接口将正式化需要的get-only属性Material:
Option Explicit
Public Property Get Symbol() As String
End Property
Public Property Get Density() As Single
End Property
Run Code Online (Sandbox Code Playgroud)
现在打开记事本并粘贴此类标题:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "StaticClass1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Run Code Online (Sandbox Code Playgroud)
它另存为StaticClass1.cls,并保持它在你的"需要频繁使用VBA代码文件"文件夹(制造一个,如果你没有一个!).
现在将原型实现添加到文本文件中:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "Material"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Implements IMaterial
Private Const mSymbol As String = ""
Private Const mDensity As Single = 0
Private Property Get IMaterial_Symbol() As String
IMaterial_Symbol = Symbol
End Property
Private Property Get IMaterial_Density() As Single
IMaterial_Density = Density
End Property
Public Property Get Symbol() As String
Symbol = mSymbol
End Property
Public Property Get Density() As Single
Density = mDensity
End Property
Run Code Online (Sandbox Code Playgroud)
将该文本文件另存为Material.cls.
现在将此类Material导入您的项目; 将其重命名为AluminiumMaterial,并填写空白:
Private Const mSymbol As String = "AL"
Private Const mDensity As Single = 169.34
Run Code Online (Sandbox Code Playgroud)
Material再次导入该类,重命名为AnotherMaterial,填写空白:
Private Const mSymbol As String = "XYZ"
Private Const mDensity As Single = 123.45
Run Code Online (Sandbox Code Playgroud)
每种材料都要冲洗和重复:每种材料只需要提供一次.
如果您正在使用Rubberduck,请将文件夹注释添加到模板文件中:
'@Folder("Materials")
Run Code Online (Sandbox Code Playgroud)
然后代码资源管理器将干净地重新组合文件夹IMaterial下的所有类Materials.
拥有"许多模块"只是VBA中的一个问题,因为VBE的Project Explorer使得它非常不方便(通过在单个"classes"文件夹下填充每个类).Rubberduck的Code Explorer不会使VBA具有命名空间,但是无论如何都可以以结构化的方式组织VBA项目.
在使用方面,您现在可以使用针对IMaterial接口编写的多态代码:
Public Sub DoSomething(ByVal material As IMaterial)
Debug.Print material.Symbol, material.Density
End Sub
Run Code Online (Sandbox Code Playgroud)
或者,您可以从公开的默认实例(从模块的VB_PredeclaredId = True属性获取)访问get-only属性:
Public Sub DoSomething()
Debug.Print AluminumMaterial.Symbol, AluminumMaterial.Density
End Sub
Run Code Online (Sandbox Code Playgroud)
您可以将默认实例传递给任何需要使用的方法IMaterial:
Public Sub DoSomething()
PrintToDebugPane AluminumMaterial
End Sub
Private Sub PrintToDebugPane(ByVal material As IMaterial)
Debug.Print material.Symbol, material.Density
End Sub
Run Code Online (Sandbox Code Playgroud)
好处是,您可以获得所有内容的编译时验证; 这些类型是不可能滥用的.
缺点是,您需要许多模块(类),如果接口需要更改,则需要更新许多类以保持代码可编译.