【问题标题】:Putting dictionaries into classes将字典放入类
【发布时间】:2017-09-01 21:50:02
【问题描述】:

几周前,我得到了一个关于如何在这个位置制作通用类模块的精彩答案:Class "let" stuck in infinite loop

老实说,我仍然不太了解,因为我 100% 的 vba 知识都是自学的,并且从这里开始,几年前的一个学期 C 中剩下的一些通用编程逻辑。但我认为我对此有很好的把握,因为这是一个很好的解释。我现在正在尝试将其应用于我的课程中的字典并遇到一些麻烦。

我的班级模块如下:

Option Explicit

Private Type categories
    Temp As scripting.Dictionary
    Humid As scripting.Dictionary
    Wind As scripting.Dictionary
End Type

Private this As categories

Public Sub Initialize()
    Set this.Temp = New scripting.Dictionary
    Set this.Humid = New scripting.Dictionary
    Set this.Wind = New scripting.Dictionary
End Sub

Public Property Get Temp(ByVal HourIndex As Long) As Double
    Temp = this.Temp(HourIndex)
End Property

Public Property Let Temp(ByVal HourIndex As Long, ByVal Value As Double)
    this.Temp(HourIndex) = Value
End Property

Public Property Get Humid(ByVal HourIndex As Long) As Double
    Humid = this.Humid(HourIndex)
End Property

Public Property Let Humid(ByVal HourIndex As Long, ByVal Value As Double)
    this.Humid(HourIndex) = Value
End Property

Public Property Get Wind(ByVal HourIndex As Long) As Double
    Wind = this.Wind(HourIndex)
End Property

Public Property Let Wind(ByVal HourIndex As Long, ByVal Value As Double)
    this.Wind(HourIndex) = Value
End Property

然后我尝试在即时窗口中使用set tester = new WeatherData(模块名称)和Initialize对此进行测试。那没有用。然后我将 Initialize 修改为:

Public Sub Initialize(ByVal variable As categories)
    Set variable.Temp = New scripting.Dictionary
    Set variable.Humid = New scripting.Dictionary
    Set variable.Wind = New scripting.Dictionary
End Sub

并输入Initialize tester,但这也不起作用(“编译错误:未定义子或函数”)。

那么,结束问题:如何将三个字典放在一个类模块中?

编辑:我是个傻瓜。以下内容本身并没有真正解决问题,但它至少绕过了它,以至于我不必承认它:

Option Explicit

Private Type categories
    Temp(23) As Double
    Humid(23) As Double
    wind(23) As Double
End Type

Private this As categories

Public Property Get Temp(ByVal HourIndex As Long) As Double
    Temp = this.Temp(HourIndex)
End Property

Public Property Let Temp(ByVal HourIndex As Long, ByVal Value As Double)
    this.Temp(HourIndex) = Value
End Property

Public Property Get Humid(ByVal HourIndex As Long) As Double
    Humid = this.Humid(HourIndex)
End Property

Public Property Let Humid(ByVal HourIndex As Long, ByVal Value As Double)
    this.Humid(HourIndex) = Value
End Property

Public Property Get wind(ByVal HourIndex As Long) As Double
    wind = this.WindChill(HourIndex)
End Property

Public Property Let wind(ByVal HourIndex As Long, ByVal Value As Double)
    this.wind(HourIndex) = Value
End Property

tl;dr:制作数组而不是字典,并完全删除初始化。你的“钥匙”别无选择,只能是数字,但至少它有效。如果有人愿意,我真的很想知道一个实际的解决方案,但我遇到的具体问题已经解决了。

【问题讨论】:

  • “它不起作用”并不是一个明确的问题陈述,但 TempHumidWind 都暴露为 Double's - 你不能分配他们到Dictionary 参考...
  • 我这样做是因为它将成为一本双打字典,尽管我不知道它是否能让我有所收获。那么这会作为一个数组工作吗?我编辑添加返回的错误是关于Initialize的编译错误。
  • Initialize 方法是WeatherData 的成员?
  • Initialize 是一个函数,可以将 24 个条目添加到 WeatherData 中的每个字典(/array/whatever 最终工作)。从那里,随着条目实际存在,它们可以更改为读取的任何数据。

标签: vba excel


【解决方案1】:

在这种情况下,您应该按如下方式使用后期绑定:

Private Type categories
    Temp As Object
    Humid As Object
    Wind As Object
End Type

Private this As categories

Public Sub Initialize()
    Set this.Temp = CreateObject("Scripting.Dictionary")
    Set this.Humid = CreateObject("Scripting.Dictionary")
    Set this.Wind = CreateObject("Scripting.Dictionary")
End Sub

此外,您不能将Let 与多个参数一起使用。你应该使用一个函数来做到这一点:

Public Function SetTemp(ByVal HourIndex As Long, ByVal Value As Double)
    this.Temp(HourIndex) = Value
End Function

为了运行这个,我使用了:

Sub test()
    Dim multi As Dictionaries
    Set multi = New Dictionaries

    multi.Initialize

    multi.SetTemp 13, 25.522
    Debug.Print multi.Temp(13)
End Sub

我的课程模块被命名为Dictionaries。所以基本上使用后期绑定并将所有多参数让函数更改为简单函数。

【讨论】:

  • 只要设置了引用,他就没有理由必须延迟绑定。尽管引用设置不正确,但仍有可能。
  • Property Let 中的多个参数有效:参见 Mathieu Guindon 示例。在您的示例中使用函数的需求似乎与 Private Type 的使用有关。
【解决方案2】:

您似乎想实现一个索引属性

简化到最低限度:

Option Explicit
Private values As Scripting.Dictionary

Private Sub Class_Initialize()
    Set values = New Scripting.Dictionary
End Sub

Public Property Get Something(ByVal key As String) As Double
    Something = values(key)
End Property

Public Property Let Something(ByVal key As String, ByVal value As Double)
    values(key) = value
End Property

您将字典安全地封装为类的实现细节(例如,外部代码不能将它们设置为Nothing),并为每个封装字典公开一个索引Get+Let 属性,这需要索引(/key)作为参数。

对于您的 WeatherData 类,这意味着您可以像这样填充数据:

Set data = New WeatherData
With data
    .Temp("day 1") = 76
    .Temp("day 2") = 78
    .Humid("day 1") = 0.55
    .Humid("day 2") = 0.61
    .Wind("day 1") = 0.92
    .Wind("day 2") = 1.27
End With

然后用data.Temp("day 1")检索"day 1"的温度。

至于您的初始化方法,它需要从类的 instance 中调用 - 作为 instance 方法

因此,您应该使用tester.Initialize 而不是Initialize tester

无论您将内部封装存储设为数组,Collection 还是 Dictionary 对调用代码都没有影响 - 这是一个封装的实现细节:您的类也可以将数据存储在 .csv 文件或如果需要,可以放入数据库中。

【讨论】:

  • 我让这个工作了一会儿,我很兴奋,但后来它停止了。我输入你的代码,然后在即时窗口中,我有set tester = new weatherdata,然后是debug.print tester.values.count,我收到一条消息,指出对象不支持该属性/方法。
  • valuesPrivate,你不能从外部访问它(这是整个重点!) - 如果你的外部代码需要知道有多少值,那么你需要公开TempItemCountHumidItemCountWindItemCount 属性以返回各自内部集合的.Count
  • 好的,所以我认为我缺少的是我引用类中的函数,而不是字典对象?我不需要访问.count,我只是将其用作测试设备以查看代码是否有效。但是,不是debug.print tester.values,而是正确的形式是tester.something(key)?如果我想放入多个字典,我将同时声明 valuesvalues2,然后将 something2something 完全相同,除了作用于 values2
  • 是的。你可以通过公开你认为合适的属性和方法来决定你想要调用代码的样子。
【解决方案3】:

我发现 Mathieu Guindon 的示例非常有启发性,但对于初学者来说却非常简约。

感谢 Mathieu Guindon,但让我分享一下他的代码的扩展版本,使用后期绑定只是为了更改一些小细节。

名为 WeatherData 的类代码模块:

'Mathieu Guindon,Feb 6 '17
'https://stackoverflow.com/a/43263480
Option Explicit
Private dTemp As Object
Private dHumid As Object
Private dWind As Object
Private Sub Class_Initialize()
    Set dTemp = CreateObject("Scripting.Dictionary")
    Set dHumid = CreateObject("Scripting.Dictionary")
    Set dWind = CreateObject("Scripting.Dictionary")
End Sub
Public Property Get Temp(ByVal key As String) As Double
    Temp = dTemp(key)
End Property
Public Property Let Temp(ByVal key As String, ByVal value As Double)
    dTemp(key) = value
End Property
Public Property Get TempItemCount() As Long
    TempItemCount = dTemp.Count
End Property
Public Property Get Humid(ByVal key As String) As Double
    Humid = dHumid(key)
End Property
Public Property Let Humid(ByVal key As String, ByVal value As Double)
    dHumid(key) = value
End Property
Public Property Get HumidItemCount() As Long
    HumidItemCount = dHumid.Count
End Property
Public Property Get Wind(ByVal key As String) As Double
    Wind = dWind(key)
End Property
Public Property Let Wind(ByVal key As String, ByVal value As Double)
    dWind(key) = value
End Property
Public Property Get WindItemCount() As Long
    WindItemCount = dWind.Count
End Property

标准代码模块:

Sub test()
Set Data = New WeatherData
With Data
    .Temp("day 1") = 76
    .Temp("day 2") = 78
    .Humid("day 1") = 0.55
    .Humid("day 2") = 0.61
    .Wind("day 1") = 0.92
    .Wind("day 2") = 1.27

    Debug.Print .Temp("day 2")
    Debug.Print .Humid("day 2")
    Debug.Print .Wind("day 2")
    Debug.Print .Wind("day 2")
    Debug.Print .TempItemCount
End With
End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    • 2015-04-10
    相关资源
    最近更新 更多