Hey all i have the following code:
Dim radarStrengthImages() As PictureBox = ({imgRadar_Strength1, imgRadar_Strength2, imgRadar_Strength3, imgRadar_Strength4, imgRadar_Strength5, imgRadar_Strength6, imgRadar_Strength7, imgRadar_Strength8})
Dim radarStrengthResourcesON() As Bitmap = ({My.Resources.radarON_16, My.Resources.radarON_17, My.Resources.radarON_18, My.Resources.radarON_19, My.Resources.radarON_20, My.Resources.radarON_21, My.Resources.radarON_22, My.Resources.radarON_23})
Dim radarStrengthResourcesOFF() As Bitmap = ({My.Resources.radar_16, My.Resources.radar_17, My.Resources.radar_18, My.Resources.radar_19, My.Resources.radar_20, My.Resources.radar_21, My.Resources.radar_22, My.Resources.radar_23})
The imgRadar_StrengthX is the name of the pictureboxes on the form itself and My.Resources.radar_XX is the image for the pictureboxes.
However when i use this code:
Dim intX As Integer = 0
Do Until intX = 8
radarStrengthImages(intX).Image = radarStrengthResourcesON(intX)
intX += 1
Loop
I get an error of:
Object reference not set to an instance of an object
and that happens on this like:
radarStrengthImages(intX).Image = radarStrengthResourcesON(intX)
This kind of code can't work, initialization order is always an important detail. The variables you use don't get a value until after the InitializeComponent() method runs. But the arrays are initialized before that happens. So you just initialize them with Nothing, nada, zippo. "Object reference not set" is the zippo exception you'll get.
You'll have to do it later, that requires moving the initializer for the array into the constructor. Generic syntax for a sample form with textboxes:
Public Class Form1
Dim boxes As TextBox()
Public Sub New()
InitializeComponent()
boxes = New TextBox() {TextBox1, TextBox2, TextBox3}
End Sub
End Class
issue is this array start at index 0 and you have 8 items
change the loop to
Do Until intX = 7
and it should now work
or if the array will change in time, use a variable to handle the max
Module Module1
Sub Main()
Dim intX As Integer = 0
Dim test(7) As Integer '8 item
Dim max = test.Length - 1
Do Until intX = max
intX += 1
Loop
Console.WriteLine("intX: " & intX)
Console.ReadKey()
End Sub
End Module
Related
I am currently writing a (multiple choice) quiz program using VB.net I have read the answer options in from a .txt file into a single dimension temporary array however I would like to split this down into each question and the answer options for each questions into a 2D array so that (0,0) would be option A for question one and then (0,1) would be Option B for question 1 etc and then (1,0) would be option A for question 2. Below is the method I have tried however I get the error: "Object reference not set to an instance of an object" when adding 1 to a variable when I try and run this section of the code optnum = optnum + 1 Any help would be greatly appreciated, either fixing my code below or suggesting another method.
Dim optnum As Integer
Dim tempq As Integer = 0
Gameload(Phase_3.sounds)
Questionnum = 0
L_start.Hide()
optnum = 0
'splits the temp array down into options for each question
For i = 0 To 39
questions(tempq, optnum) = temparray(i)
optnum = optnum + 1
'there are 4 options for each question
'moves on to the next question when there is 4 options in the question
If optnum = 3 Then
tempq = tempq + 1
optnum = 0
End If
Next
For i = 0 To 3
L_option1.Text = questions(0, i)
Next
question_set()
Edit:
Here is the new full code I am still getting the error: Object reference not set to an instance of an object but now at the next in this section of code.
'''
For optnum = 0 To 3
questions(i, optnum) = temparray(i * 4 + optnum)
Next
'''
Thank you for all the help so far
'''
Public Class Game
Dim submission As Integer
Dim Correct_ans As Integer
Dim temparray() As String
Dim questions(,) As String
Dim Questionnum As Integer
Dim rs As New Resizer
Private Sub Game_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'finds all components on the screen in preperation if the screen resizes
rs.FindAllControls(Me)
L_start.Show()
End Sub
Private Sub Game_Resize(sender As Object, e As EventArgs) Handles Me.Resize
'resizes all components on the screen to same proportions
rs.ResizeAllControls(Me)
End Sub
Sub Gameload(ByVal sounds As String)
Dim pack As String
'reads in the sound pack
pack = My.Resources.ResourceManager.GetString(sounds)
Phase_3.Close()
'splits the pack into an array so that it can be broken down into questions
temparray = pack.Split(","c)
End Sub
Sub L_start_Click(sender As Object, e As EventArgs) Handles L_start.Click
Dim optnum As Integer
Dim tempq As Integer = 0
Gameload(Phase_3.sounds)
Questionnum = 0
L_start.Hide()
optnum = 0
'splits the temp array down into options for each question
For i = 0 To temparray.Count / 4
For optnum = 0 To 3
questions(i, optnum) = temparray(i * 4 + optnum)
Next
Next
For i = 0 To 3
L_option1.Text = questions(0, i)
Next
End Sub
'''
This is just my opinion but I think your aproach would be hard to maintain. I never saw the value of a class until I actually tried one. Maybe this is your chance.
Public Class Quiz
Public Property QuestionNumber As Integer
Public Property Question As String
Public Property AnswerA As String
Public Property AnswerB As String
Public Property AnswerC As String
Public Property AnswerD As String
Public Property CorrectAnswer As String
Public Overrides Function ToString() As String
Return $"Question: {QuestionNumber}.{Question} Answer Choices: {AnswerA}, {AnswerB}, {AnswerC}, {AnswerD} Correct Answer - {CorrectAnswer}"
End Function
End Class
To use your class...
Private QuestionList As New List(Of Quiz)
Private Sub OPCode2()
Dim temparray = File.ReadAllLines("answers.txt")
Dim temparraylocation As Integer
Dim questions = File.ReadAllLines("questions.txt")
Dim correctAnswers = File.ReadAllLines("correct.txt")
For i = 0 To questions.Length - 1
Dim qu As New Quiz
qu.QuestionNumber = i + 1
qu.Question = questions(i)
qu.CorrectAnswer = correctAnswers(i)
qu.AnswerA = temparray(temparraylocation)
temparraylocation += 1
qu.AnswerB = temparray(temparraylocation)
temparraylocation += 1
qu.AnswerC = temparray(temparraylocation)
temparraylocation += 1
qu.AnswerD = temparray(temparraylocation)
temparraylocation += 1
QuestionList.Add(qu)
Next
For Each q In QuestionList
Debug.Print(q.ToString)
Next
End Sub
Where's your declaration for temparray and questions. Will the quiz always have 4 choices and 10 questions?
It might be easier for you to have a nested loop so that i is temparray.count/4 and optnum is 0-3, then you can populate questions(i, optnum) = temparray(i*4+optnum)
Looking at your new code, you haven't initialised the questions variable. Only declared it.
Personally I would change questions to a list(of question), then use Mary's answer.
I just recently moved from VB6 to VB.NET and I'm recoding an old app. So I'm pretty unexperienced with .NET so far.
I have multiple (lets say 4 in this code example) twodimensional string arrays (or actually an array of arrays) which I want to store as a ComboBox items ie. one twodimensional array is one item.
Public Class MyItem
Private sName As String
Private sArr As Array()
Public Sub New(ByVal Name As String, ParamArray Arr As Array())
sName = Name
sArr = Arr
End Sub
Public Property Arr() As Array()
Get
Return sArr
End Get
Set(ByVal sValue As Array())
sArr = sValue
End Set
End Property
Public Overrides Function ToString() As String
Return sName
End Function
End Class
---
Dim sMyArray as Array()
For i As Integer = 0 to 3
sMyArray = Nothing ' resetting the array before refilling it
'
' No code here but filling sMyArray by reading a text file, each line
' number as dim 1 and splitted each line into dim 2 with ";" using Split(sRead, ";")
' so Debub.Print(sMyArray(0)(0)) prints the beginning of the first line until first ";" <- this works fine
'
' Then passing sMyArray to a ComboBox item
'
ComboBox.Items.Add(New MyItem("item" & i, sMyArray))
Next i
The problem is that when recovering the arrays from ComboCox items only the last ComboBox item has array data. So for example
Dim sMyNewArray As Array() = ComboBox.Items.Item(0).Arr
Debug.Print(sMyNewArray(0)(0))
throws an error while
Dim sMyNewArray As Array() = ComboBox.Items.Item(3).Arr
Debug.Print(UBound(sMyNewArray(UBound(sMyNewArray))))
does not and prints the last item's last row's ubound
Can anyone figure out what is it I'm missing or tell me a better way to do this? I'm pretty sure there is one..
I'm not 100% sure, but I think the problem is in this section:
Dim sMyArray as Array()
For i As Integer = 0 to 3
sMyArray = Nothing ' resetting the array before refilling it
Arrays are technically reference types, but like strings, there's some extra compiler magic to make them feel at times more like value types, and I have a sense in this case the actual sMyArray reference was used (perhaps because of a ParamArrays optimzation), such that setting it to Nothing broke things. The more idiomatic way to write this code for .Net it like this:
For i As Integer = 0 to 3
Dim sMyArray as Array()
.Net has a much more sophisticated garbage collector than was available for VB6. We don't often set variables to Nothing any more, but instead just re-assign them or let them fall out of scope. In fact, setting a variable to Nothing can in rare cases be actively harmful. Moreover, we want to see the Dim keyword inside the loop, so you're working with a different variable on each iteration, with the smallest possible scope.
While I'm here, in .Net we pretty much never use the base Array type. Instead of this:
Private sArr As Array()
You pretty much always do this:
Private arr As String()()
or this, for true two-dimensional (non-jagged) arrays:
Private arr As String(,)
or, best of all, this:
Private arr As New List(Of String())
Since VB.Net has more collection types than just array.
Also, I don't have the link handy, but Microsoft's coding guidelines now explicitly ask you not to use hungarian warts for variable and class names (so sArr can just be arr). This is a change from the VB6 era because of changes to the language where the type is more likely to be implicit with the variable and improvements to the tooling, where the prefixes usually no longer add much utility and have been shown to hurt readability.
Not really sure why you have a 2 dimensional array, but here is a small sample NOT using the Array type. It uses just plain strings and string arrays. Let me know if this helps. This splits a few strings, then reads out the results after populating.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim sMyArray()() As String
Dim line1 As String = "a;b;c;d 1;2;3;4;5"
Dim line2 As String = "z;x;y;w 99;65;32;21;18"
sMyArray = ParseString(line1)
cboBox1.Items.Add(New MyItem("System0", sMyArray))
sMyArray = ParseString(line2)
cboBox1.Items.Add(New MyItem("System1", sMyArray))
For i As Integer = 0 To cboBox1.Items.Count - 1
For j As Integer = 0 To UBound(cboBox1.Items(i).arr)
For k As Integer = 0 To UBound(cboBox1.Items(i).arr(j))
Debug.Write(cboBox1.Items(i).arr(j)(k) & " ")
Next
Next
Debug.WriteLine("")
Next
End Sub
Private Function ParseString(s As String) As String()()
Dim rows As String() = s.Split(" ")
Dim matrix As String()() = New String(rows.Length - 1)() {}
For i As Integer = 0 To rows.Length - 1
matrix(i) = rows(i).Split(";")
Next
Return matrix
End Function
End Class
Public Class MyItem
Private sName As String
Private sArr As String()()
Public Sub New(ByVal Name As String, ByVal ParamArray Arr As String()())
sName = Name
sArr = Arr
End Sub
Public Property Arr() As String()()
Get
Return sArr
End Get
Set(ByVal sValue As String()())
sArr = sValue
End Set
End Property
Public Overrides Function ToString() As String
Return sName
End Function
End Class
my VBA-code is making trouble. I made a Class module called "clsColl" with the Properties. When i declare a variable as "clsColl" everything working fine, but when i declare an array as "clsColl" i get an error
"Object variable or With block variable not set", if i use this array in another sub, which i called in the first sub.
I made a short example with just the code in it which making trouble.
First my class module "clsColl"
Option Explicit
Public name As String
Public weight as single
Now the code which is working
Sub workingA()
Dim persona As New clsColl
Call workingB(persona)
End Sub
Sub workingB(persona As cls Coll)
persona.name = "phil"
persona.weight = 100
End Sub
Now the code which is not working
Sub failingA()
Dim persona() As New clsColl
ReDim persona(1 to 5)
Call failingB(persona)
End Sub
Sub failingB(persona() As cls Coll)
persona(1).name = "phil"
persona(1).weight = 100
End Sub
I get an error, just by changing my code from using a variable to using an array.
Now i get an error Object variable or With block variable not set" with the second code, but i don't know why. I want to know why using an array as an object is making trouble like this, while using a normal variable is working fine.
Your code line
Dim persona As New clsColl
is a combination of
Dim persona As clsColl
If persona Is Nothing Then Set persona = New clsColl
and it is bad practice using that combining syntax at all, at least in my opionion.
Now for the array this cannot work anymore as each array item must be Set to be an clsColl object first:
Sub notMorefailingA()
Dim persona() As clsColl
Dim i As Integer
ReDim persona(1 To 5)
For i = 1 To 5
Set persona(i) = New clsColl
Next
Call notMorefailingB(persona)
End Sub
Sub notMorefailingB(persona() As clsColl)
persona(1).name = "phil"
persona(1).weight = 100
End Sub
You have nothing in the array you need to populate the array with classes. Your Dim wont use the new keyword, you'll create new classes and add them into the array.
Sub test1()
Dim d As New clsDimension
Dim arrDimensions(5) As clsDimension
Set arrDimensions(0) = d
arrDimensions(0).Breadth = 100
arrDimensions(0).Depth = 200
End Sub
or in a similar approach to your post
A class for the array, like so, clsDimensionArray
Private arrDimensions() As clsDimension
Public Property Get ArrItems(x As Long) As clsDimension
Set ArrItems = arrDimensions(x)
End Property
Public Sub Create(lngSize As Long)
Dim l As Long
Dim d As clsDimension
ReDim arrDimensions(lngSize - 1)
For l = 0 To UBound(arrDimensions)
Set d = New clsDimension
Set arrDimensions(l) = d
Set d = Nothing
Next l
End Sub
and using like so
Sub test1()
Dim arrDimensions As New clsDimensionArray
arrDimensions.Create (100)
arrDimensions.ArrItems(90).Depth = 50
arrDimensions.ArrItems(90).Breadth = 100
End Sub
Keeps it nice and tidy :o)
I'm designing a dynamic buffer for outgoing messages. The data structure takes the form of a queue of nodes that have a Byte Array buffer as a member. Unfortunately in VBA, Arrays cannot be public members of a class.
For example, this is a no-no and will not compile:
'clsTest
Public Buffer() As Byte
You will get the following error: "Constants, fixed-length strings, arrays, user-defined types and Declare statements not allowed as Public members of object modules"
Well, that's fine, I'll just make it a private member with public Property accessors...
'clsTest
Private m_Buffer() As Byte
Public Property Let Buffer(buf() As Byte)
m_Buffer = buf
End Property
Public Property Get Buffer() As Byte()
Buffer = m_Buffer
End Property
...and then a few tests in a module to make sure it works:
'mdlMain
Public Sub Main()
Dim buf() As Byte
ReDim buf(0 To 4)
buf(0) = 1
buf(1) = 2
buf(2) = 3
buf(3) = 4
Dim oBuffer As clsTest
Set oBuffer = New clsTest
'Test #1, the assignment
oBuffer.Buffer = buf 'Success!
'Test #2, get the value of an index in the array
' Debug.Print oBuffer.Buffer(2) 'Fail
Debug.Print oBuffer.Buffer()(2) 'Success! This is from GSerg's comment
'Test #3, change the value of an index in the array and verify that it is actually modified
oBuffer.Buffer()(2) = 27
Debug.Print oBuffer.Buffer()(2) 'Fail, diplays "3" in the immediate window
End Sub
Test #1 works fine, but Test #2 breaks, Buffer is highlighted, and the error message is "Wrong number of arguments or invalid property assignment"
Test #2 now works! GSerg points out that in order to call the Property Get Buffer() correctly and also refer to a specific index in the buffer, TWO sets of parenthesis are necessary: oBuffer.Buffer()(2)
Test #3 fails - the original value of 3 is printed to the Immediate window. GSerg pointed out in his comment that the Public Property Get Buffer() only returns a copy and not the actual class member array, so modifications are lost.
How can this third issue be resolved make the class member array work as expected?
(I should clarify that the general question is "VBA doesn't allow arrays to be public members of classes. How can I get around this to have an array member of a class that behaves as if it was for all practical purposes including: #1 assigning the array, #2 getting values from the array, #3 assigning values in the array and #4 using the array directly in a call to CopyMemory (#3 and #4 are nearly equivalent)?)"
So it turns out I needed a little help from OleAut32.dll, specifically the 'VariantCopy' function. This function faithfully makes an exact copy of one Variant to another, including when it is ByRef!
'clsTest
Private Declare Sub VariantCopy Lib "OleAut32" (pvarDest As Any, pvargSrc As Any)
Private m_Buffer() As Byte
Public Property Let Buffer(buf As Variant)
m_Buffer = buf
End Property
Public Property Get Buffer() As Variant
Buffer = GetByRefVariant(m_Buffer)
End Property
Private Function GetByRefVariant(ByRef var As Variant) As Variant
VariantCopy GetByRefVariant, var
End Function
With this new definition, all the tests pass!
'mdlMain
Public Sub Main()
Dim buf() As Byte
ReDim buf(0 To 4)
buf(0) = 1
buf(1) = 2
buf(2) = 3
buf(3) = 4
Dim oBuffer As clsTest
Set oBuffer = New clsTest
'Test #1, the assignment
oBuffer.Buffer = buf 'Success!
'Test #2, get the value of an index in the array
Debug.Print oBuffer.Buffer()(2) 'Success! This is from GSerg's comment on the question
'Test #3, change the value of an index in the array and verify that it is actually modified
oBuffer.Buffer()(2) = 27
Debug.Print oBuffer.Buffer()(2) 'Success! Diplays "27" in the immediate window
End Sub
#Blackhawk,
I know it is an old post, but thought I'd post it anyway.
Below is a code I used to add an array of points to a class, I used a subclass to define the individual points, it sounds your challenge is similar:
Mainclass tCurve
Private pMaxAmplitude As Double
Private pCurvePoints() As cCurvePoint
Public cDay As Date
Public MaxGrad As Double
Public GradChange As New intCollection
Public TideMax As New intCollection
Public TideMin As New intCollection
Public TideAmplitude As New intCollection
Public TideLow As New intCollection
Public TideHigh As New intCollection
Private Sub Class_Initialize()
ReDim pCurvePoints(1 To 1500)
ReDim curvePoints(1 To 1500) As cCurvePoint
Dim i As Integer
For i = 1 To 1500
Set Me.curvePoint(i) = New cCurvePoint
Next
End Sub
Public Property Get curvePoint(Index As Integer) As cCurvePoint
Set curvePoint = pCurvePoints(Index)
End Property
Public Property Set curvePoint(Index As Integer, Value As cCurvePoint)
Set pCurvePoints(Index) = Value
End Property
subclass cCurvePoint
Option Explicit
Private pSlope As Double
Private pCurvature As Double
Private pY As Variant
Private pdY As Double
Private pRadius As Double
Private pArcLen As Double
Private pChordLen As Double
Public Property Let Slope(Value As Double)
pSlope = Value
End Property
Public Property Get Slope() As Double
Slope = pSlope
End Property
Public Property Let Curvature(Value As Double)
pCurvature = Value
End Property
Public Property Get Curvature() As Double
Curvature = pCurvature
End Property
Public Property Let valY(Value As Double)
pY = Value
End Property
Public Property Get valY() As Double
valY = pY
End Property
Public Property Let Radius(Value As Double)
pRadius = Value
End Property
Public Property Get Radius() As Double
Radius = pRadius
End Property
Public Property Let ArcLen(Value As Double)
pArcLen = Value
End Property
Public Property Get ArcLen() As Double
ArcLen = pArcLen
End Property
Public Property Let ChordLen(Value As Double)
pChordLen = Value
End Property
Public Property Get ChordLen() As Double
ChordLen = pChordLen
End Property
Public Property Let dY(Value As Double)
pdY = Value
End Property
Public Property Get dY() As Double
dY = pdY
End Property
This will create a tCurve with 1500 tCurve.Curvepoints().dY (for example)
The trick is to get the index process correct in the main class !
Good luck !
Not the most elegant solution, but modeling from the code you provided...
In clsTest:
Option Explicit
Dim ArrayStore() As Byte
Public Sub AssignArray(vInput As Variant, Optional lItemNum As Long = -1)
If Not lItemNum = -1 Then
ArrayStore(lItemNum) = vInput
Else
ArrayStore() = vInput
End If
End Sub
Public Function GetArrayValue(lItemNum As Long) As Byte
GetArrayValue = ArrayStore(lItemNum)
End Function
Public Function GetWholeArray() As Byte()
ReDim GetWholeArray(LBound(ArrayStore) To UBound(ArrayStore))
GetWholeArray = ArrayStore
End Function
And in mdlMain:
Sub test()
Dim buf() As Byte
Dim bufnew() As Byte
Dim oBuffer As New clsTest
ReDim buf(0 To 4)
buf(0) = 1
buf(1) = 2
buf(2) = 3
buf(3) = 4
oBuffer.AssignArray vInput:=buf
Debug.Print oBuffer.GetArrayValue(lItemNum:=2)
oBuffer.AssignArray vInput:=27, lItemNum:=2
Debug.Print oBuffer.GetArrayValue(lItemNum:=2)
bufnew() = oBuffer.GetWholeArray
Debug.Print bufnew(0)
Debug.Print bufnew(1)
Debug.Print bufnew(2)
Debug.Print bufnew(3)
End Sub
I added code to pass the class array to another array to prove accessibility.
Even though VBA won't allow us to pass arrays as properties, we can still use Functions to pick up where properties fall short.
If arrays are returned by reference, why doesn't the following work:
'Class1 class module
Private v() As Double
Public Property Get Vec() As Double()
Vec = v()
End Property
Private Sub Class_Initialize()
ReDim v(0 To 3)
End Sub
' end class module
Sub Test1()
Dim c As Class1
Set c = New Class1
Debug.Print c.Vec()(1) ' prints 0 as expected
c.Vec()(1) = 5.6
Debug.Print c.Vec()(1) ' still prints 0
End Sub
You don't have a let property. Also, the get property is returning the entire array, rather than just the element in question. Change the return type of Property Get from Double() to just plain Double. Add Property Let. Note that it takes two inputs, but only one is passed to it. The last variable (MyValue, in this case) is assumed to get it's value from whatever is after the = sign. Put a break point somewhere early in Test1() and see how the values are affected in the Locals window. Compare the variables created by the original code versus my code:
'Class1 class module
Private v() As Double
Public Property Get Vec(index As Long) As Double
Vec = v(index)
End Property
Public Property Let Vec(index As Long, MyValue As Double)
v(index) = MyValue
End Property
Private Sub Class_Initialize()
ReDim v(0 To 3)
End Sub
' end class module
'Begin module
Sub Test1()
Dim c As Class1
Set c = New Class1
Debug.Print c.Vec(1) ' prints 0 as expected
c.Vec(1) = 5.6
Debug.Print c.Vec(1) ' prints 5.6
End Sub
'End module
In VBA, arrays are never returned by reference unless they are returned through a ByRef parameter. Furthermore, whenever you use = to assign an array to a variable, you've made a new copy of the array, even if you're assigning it to a ByRef argument inside of a procedure, so you're pretty much out of luck trying to make this work.
Some alternative are...
Use a VBA.Collection instead of an array.
Make your own class that encapsulates an array and exposes procedures for indirectly accessing and manipulating the internal array.
I want to suggest another nice way to do this using a Collection and a static Property without the need to use a class:
imagine you want to have the xlCVError enum as an array (or collection), e.g. to loop through it on errors and handle it based on the actual error.
The following is initialized once on access:
'from https://stackoverflow.com/a/56646199/1915920
Static Property Get XlCVErrorColl() As Collection
Dim c As Collection 'will be already initalized after 1st access
'because of "Static Property" above!
Set XlCVErrorColl = c
If Not c Is Nothing Then Exit Property
'initialize once:
Set c = New Collection
c.Add XlCVError.xlErrDiv0
c.Add XlCVError.xlErrNA
c.Add XlCVError.xlErrName
c.Add XlCVError.xlErrNull
c.Add XlCVError.xlErrNum
c.Add XlCVError.xlErrRef
c.Add XlCVError.xlErrValue
Set XlCVErrorColl = c
End Property
Turning this into an array or implementing it as an array is straight forward, but collections seem to be more useful to me, with the disadvantage that their elements are not implicitely typed/(compile-time-)type checked.
So this would e.g. turn it into an (read-only) array (with the in-mem-copy-disadvantage mentioned in other answers/comments):
'from https://stackoverflow.com/a/56646199/1915920
Static Property Get XlCVErrorArr() As XlCVError()
Dim a() As XlCVError
XlCVErrorArr = a
If UBound( a ) > 0 Then Exit Property
'initialize once:
Dim c As Collection: Set c = XlCVErrorColl
ReDim a(c.Count)
Dim i As Integer: For i = 1 To c.Count
a(i) = c(i)
Next i
XlCVErrorArr = a
End Function
So transforming the example from Clayton Ss answer into a static, modifiable module property using some array it would be:
'module (no class required)
'from https://stackoverflow.com/a/56646199/1915920
Private v() As Double
Static Property Get Vec(index As Long) As Double
If UBound(v) < 3 Then 'initialize once:
ReDim v(0 To 3) 'one could initialize it with anyting after here too
end if
Vec = v(index)
End Property
Public Property Let Vec(index As Long, MyValue As Double)
v(index) = MyValue
End Property