【问题标题】:Unable to find a way to store data into an array inside a class module无法找到将数据存储到类模块内的数组中的方法
【发布时间】:2023-03-13 05:00:01
【问题描述】:

我一直在努力解决这个问题。我的问题是我有一堆 JSON 数据,我想将其表示为对象。

数组有问题。

我创建了一个类模块,例如 FancyCat,其名称为 public Name as String

然后我可以设置这个

Dim MyFancyCat as FancyCat
Set MyFancyCat = new FancyCat

FancyCat.Name = JSONData("Name")

我是凭记忆输入的,但我认为它是正确的。 Anyhoo,它工作正常。

问题是一只花哨的猫有几双袜子。袜子的数量是可变的。

在 vba 中,由于某种原因,您不能拥有公共数组。所以这段代码是非法的:

public Socks() as FancySock 'Illegal

查看 SO,我找到了两种解决方案,一种是将其设为私有并使用属性来访问它,另一种是将其声明为 Variant,然后稍后将数组插入其中。

我填充这个数组的方法是检查 JSON 数组以获取 Count,然后到 ReDim 匹配数组,然后填充它。

问题是我的ReDim 语句拒绝工作。

似乎我无法重新调整属性,出现错误。而且我在尝试重新调整公共变体字段时也遇到错误。如果我声明一个本地数组并重新调整它,我的 ReDim 工作正常,所以我可能会这样做,然后将其分配给属性......但我无法直接重新调整它似乎很奇怪。

知道为什么它不起作用吗?

使用上面的 Variant 方法,我的代码是:

ReDim MyFancyCat.Socks(socksLength) As FancySocks

在 FancyCat 类模块中:

public Socks As Variant

我收到Method or Data Member Not Found

另一种方法的错误不同,但我重新调整了所有代码以尝试第二种方法,所以我不确定它是什么。


编辑:我将更清楚地解释我想要做的事情。我有一些 JSON 数据进来,我想将其存储为对象层次结构。

在 C# 中我会这样做(没有 linq 快捷方式的伪代码):

var myData = ReadJsonData(); // Produces a kind of dictionary

var myFancyCat = new FancyCat();

myFancyCat.Name = myData["Name"];
myFancyCat.Age = myData["Age"];
myFancyCat.Socks = new List<FancySock>();

foreach (var sock in myData["Socks"])
{
    myFancyCat.Socks.Add(sock);
}

在 excel 中我想做同样的事情。

所以我为FancyCatFancySock 创建了一个类模块,并为FancyCat 提供了姓名、年龄等的公共成员,但是我还想要我的猫拥有的一系列袜子。我想用强类型引用来做到这一点,例如我上面的 c# 代码我可以做到:

myFancyCat.Socks[0].Colour // Intellisense works, shows colour as a property

但是,在 excel 中,您似乎不能公开声明数组。因此,您可以根据 cmets 通过将其声明为 variant 来解决此问题,然后无论如何都粘贴一个数组,但您会失去智能感知。或者,您可以使用 get/let 属性,它有点工作,但更繁琐,因为您似乎无法使用 get/let 实际公开数组,您必须让它获取索引并单独公开元素。

所以此时我想忘记它没有发生的强类型,也许使用集合?

FancySock 类中可能有更多的嵌套数组。我读过没有ByRef 用于数组(至少,不完全 - 我认为你可以得到一个数组 ByRef 但不能设置一个?)。我不确定这是否会在尝试设置它时产生问题。

但最终,我只想以 OO 方式轻松表示我的 JSON 数据,以便在我的 excel 中最终我可以做到

myFancyCat.NamemyFancyCat.Socks.CountmyFancyCat.Socks(1).Colour

在 vba 中将 JSON 反序列化为“对象”似乎比看起来要困难得多。

【问题讨论】:

  • 只需使用collection 而不是数组。
  • 我考虑过,但我读到集合有点慢并且没有类型。我希望通过使用数组来保留智能感知。另外,我正在将特定大小的数据数组从 json 复制到数组中,因此不需要动态调整大小。然而,考虑到困难,这也许是最好的方法。
  • 在您的班级中使用公共子来处理分配和调整大小,而不是使用 Property Let。有一个属性 Get 来检索它。
  • 您可以尝试声明Socks As Variant(不带括号)。然后您可以简单地将数组设置为Socks = myArray... 不需要DimReDim。即使您第二次放置不同维度的数组。
  • VBA 在将变量声明为Variant 时非常灵活。或者简单的Dim SocksVariant 是隐含的。

标签: excel vba


【解决方案1】:

请尝试下一个方法:

  1. 插入一个类模块,将其命名为FancyCat并复制下一段代码:
Option Explicit

Private arrL As Object
Public myName As String, myAge As Long

Public Sub Class_Initialize()
    Set arrL = CreateObject("System.Collections.ArrayList")
End Sub
Public Property Let Name(strName As String)
   myName = strName
End Property
Public Property Let Age(lngAge As String)
   myAge = lngAge
End Property
Public Property Let SocksAdd(sMember)
   arrL.Add sMember
End Property

Public Property Get Socks() As Variant
   Socks = arrL.toarray()
End Property
  1. 在接下来的测试中使用它Sub
Sub testClassDictListArray()
  Dim myFancyCat As New FancyCat, myData As Object
  Dim arrSocks, sock
  
  Set myData = CreateObject("Scripting.Dictionary")           'this should be the dictionary returned by ParseJSON
  myData.Add "Name", "John Doe": myData.Add "Age", 35
  myData.Add "Socks", Array("Blue", "White", "Red", "Green", "Yellow")
  
  myFancyCat.Name = myData("Name")
  myFancyCat.Age = myData("Age")
  For Each sock In myData("Socks")
        myFancyCat.SocksAdd = sock
  Next sock
  
  arrSocks = myFancyCat.Socks
  Debug.Print Join(arrSocks, "|")
End Sub

我不确定我是否完全理解您尝试讨论的场景...

如果您想从 instellisense 建议中受益,我会告诉您要添加哪些参考。甚至,我会发送两段代码来自动添加必要的引用(我的意思是,Scripting.Dictionary 和 ArrayList`)。

请进行测试并发送一些反馈。

【讨论】:

  • 我认为这会起作用,我希望避免使用变体,但我想没有太多选择。我认为即使使用 byref,excel 也不会对数组进行引用,因此集合可能会更好,但老实说,我找不到明确的解释来解释为什么要使用一个而不是另一个...
  • @NibblyPig 解释一下你想要完成的事情不是更好吗?如果我们知道您的目标是什么,我们也许可以更好地提出解决方案...
  • 我已经更新了我的问题来解释。我基本上只是想将json加载到类模块中。
  • @NibblyPig 请测试更新的代码并发送一些反馈。
【解决方案2】:

在你的课堂上:

Private m_Name As String
Private m_Socks() As String

Public Property Let Name(Name As String)
    m_Name = Name
End Property

Public Property Get Name() As String
    Name = m_Name
End Property

Public Sub SetSize(Quantity As Long)
    ReDim m_Socks(1 To Quantity)
End Sub

Public Property Let Socks(Index As Long, Sock As String)
        m_Socks(Index) = Sock
End Property

Public Property Get Socks(Index As Long) As String
    Socks = m_Socks(Index)
End Property

在常规模块中:

Sub UseFancyCat()

    Dim MyFancyCat As FancyCat
    Set MyFancyCat = New FancyCat
    
    MyFancyCat.Name = "Fancy Name"
    MyFancyCat.SetSize 2
    MyFancyCat.Socks(1) = "Sock1"
    MyFancyCat.Socks(2) = "Sock2"
    
    Debug.Print MyFancyCat.Name
    Debug.Print MyFancyCat.Socks(1)
    Debug.Print MyFancyCat.Socks(2)

End Sub

【讨论】:

  • 谢谢。这是很多代码,我希望只做一个简单的 redim,但如果这是唯一的方法,那就这样吧。我很想知道为什么 ReDim 不起作用,也许它只适用于局部变量或其他东西。
  • 我收到一个编译错误,Definitions of property procedures for the same property are inconsistent, or property procedure has an optional parameter, a ParamArray or an invalid Set final parameter。我的代码中唯一的区别是我没有使用字符串,我使用的是类模块。您的示例使用 Socks 作为字符串,但 Socks 是对象而不是字符串?
猜你喜欢
  • 1970-01-01
  • 2017-09-05
  • 2021-10-02
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多