error 91, variable not set can't use a getter - excel

I can't use my Property Get in my main program.
I have already got this problem with the constructor of my class, I put Set before every property.
Public ID As Integer
Public numberOfError As Integer
Public error1 As Erreur
Public error2 As Erreur
Public error3 As Erreur
Public error4 As Erreur
Public Sub ajouterDTC(bid As Integer, Optional bnumberOfError As Integer, Optional berror1 As Erreur, Optional berror2 As Erreur, Optional berror3 As Erreur, Optional berror4 As Erreur)
With Me
.ID = bid
.numberOfError = bnumberOfError
Set .error1 = berror1
Set .error2 = berror2
Set .error3 = berror3
Set .error4 = berror4
End With
End Sub
'error1 properties
Public Property Get getError1() As Erreur
getError1 = error1
End Property
Public Property Let letError1(berror1 As Erreur)
error1 = berror1
End Property

"Erreur is still an object, so you need to Set it. Set getError1 = error1."
by Vincent G

Related

Accessing an object property from within another object that contains it

I'll try to explain it to the best of my ability with my limited knowledge...
I have a square matrix, same amount of rows and columns, i need to loop thru it and store the information of each cell in a certain way, i've done it previously with arrays and got everything working, but i'm trying to improve on my coding skills, and i've known for a while that objects are the way to go usually... this is my second attempt after quite a while of just not trying due to being defeated...
The thing is... I have 2 objects, one named Proveedor, this guy will have 3 properties:
Unidad Decisoria_Prov: a string
Responsable_Prov: a string
Requerimientos: an array of Vinculo objects
Private pedidos_() As Vinculo
Private ud_P As String
Private responsable_P As String
Option Explicit
Public Property Let Requerimientos(index As Integer, str As Vinculo)
If index > UBound(pedidos_) Then ReDim Preserve pedidos_(index)
If pedidos_(index) Is Nothing Then
Set pedidos_(index) = New Vinculo
End If
Set pedidos_(index) = str
End Property
Public Property Get Requerimientos(index As Integer) As Vinculo
If index > UBound(pedidos_) Then Requerimientos = "El indice del get esta fuera de rango": Exit Property
Requerimientos = pedidos_(index)
End Property
Public Property Let Unidad_Decisoria_Prov(str As String)
ud_P = str
End Property
Public Property Get Unidad_Decisoria_Prov() As String
Unidad_Decisoria_Prov = ud_P
End Property
Public Property Let Responsable_Prov(str As String)
responsable_P = str
End Property
Public Property Get Responsable_Prov() As String
Responsable_Prov = responsable_P
End Property
Private Sub class_initialize()
ReDim pedidos_(0)
End Sub
The other object is named Vinculo, this one has 3 properties:
Unidad Decisoria_C: a string
Responsable_C: a string
Requerimiento: a string
Private ud_ As String
Private responsable_ As String
Private requerimiento_ As String
Option Explicit
Public Property Let Unidad_Decisoria_C(str As String)
ud_ = str
End Property
Public Property Get Unidad_Decisoria_C() As String
Unidad_Decisoria_C = ud_
End Property
Public Property Let Responsable_C(str As String)
responsable_ = str
End Property
Public Property Get Responsable_C() As String
Responsable_C = responsable_
End Property
Public Property Let Requerimiento(str As String)
requerimiento_ = str
End Property
Public Property Get Requerimiento() As String
Requerimiento = requerimiento_
End Property
Once I have the objects working as intended i'll loop thru the matrix and do what i need to with the data, but before wasting time on that, i'm trying to test it with the following code:
Sub testing_2_objetosjuntos()
Dim mi_Prov As Proveedor
Dim un_vin As Vinculo
Set mi_Prov = New Proveedor
Set un_vin = New Vinculo
mi_Prov.Unidad_Decisoria_Prov = "tarea del proveedor 1"
mi_Prov.Responsable_Prov = "responsable de la tarea del proveedor 1"
un_vin.Unidad_Decisoria_C = "tarea del cliente 1"
un_vin.Responsable_C = "responsable de la tarea 1 del cliente"
un_vin.Requerimiento = "hace tal cosa"
mi_Prov.Requerimientos(0) = un_vin
Debug.Print mi_Prov.Requerimientos(0).Requerimiento
Debug.Print mi_Prov.Requerimientos(0).Responsable_C
End Sub
Up to the debug.print command everything works fine as far as i can tell...
watches up until the first debug.print line
however when i try to access the properties of the vinculo object stored in the first index of the Proveedor object i get a beautiful
Run-time error 91:
Object variable or With block variable not set
The actual line that gives me that error is the get property of Requerimientos in the Proveedor class.
This is probably a silly question but not only i can't understand why it breaks, i'm unable to apparently ask the question properly in google to not have to bother you guys...
I expected to read the string stored in the vinculo.Requerimiento property which is in the first index of the array of Requerimientos property of the Proveedor object.
The reason for your problem is easy to fix. As Vinculo is an object, you need to use the Set keyword in the Requerimientos-getter:
Public Property Get Requerimientos(index As Integer) As Vinculo
Set Requerimientos = pedidos_(index)
End Property
However, your error handling will fail: If index > UBound(pedidos_), you are assigning a String as return value which is not allowed (remember, your function returns an object of type Vinculo, not a String).
You should raise an error instead
Public Property Get Requerimientos(index As Integer) As Vinculo
Err.Raise vbObjectError + 1000, "El indice del get esta fuera de rango", "Sorry..."
Set Requerimientos = pedidos_(index)
End Property
And a hint: You had problems to identify the error of your test routine because the VBA runtime didn't halt on the line of error. This is because the default setting of the VBA debugger is "Break on unhandled errors" which doesn't include to break within a class module (hint: Userforms are also classes). Change this setting to "Break in class modules" to see the exact line where the error occurs.
Tools->Options->General

VBA - Class Module - access to property by index

is there way how to make class working similar to Arrays?
Let's say, I have Class (e.g. Workers) where main property is array of the Workers, nothing else.
Then I'm filling the class as follows
Dim wks as new Workers
wks.add("Worker1")
wks.add("Worker2")
wks.add("Worker3")
Then in Workers Class module:
Private Workers as Variant
Public Function add(ByVal val As Variant) As Long
ReDim Preserve Workers(LBound(Workers) To UBound(Workers) + 1)
Workers(UBound(Workers)) = val
add = UBound(Workers) - LBound(Workers) +1
End Function
Workers representation -> {"Worker1", "Worker2", "Worker3"}
Then I want to access Worker by its index. I know, how to access it by e.g wks.getWorker(1) but what I want to do, is to access it directly by wks(1) which should return "Worker 1". Example above looks, that usual Array or Collection can be used, but I have many internal methods done, only what I'm missing is to access Workers property to read/write directly by its index number.
Is it possible?
Edit
After transfer to Collections, Class looks like:
Option Explicit
Private Workers As Collection
Private Sub Class_Initialize()
Set Workers = New Collection
End Sub
Public Function add(ByVal val As Variant) As Long
Workers.add val
End Function
Public Property Get Item(Index As Integer) As Variant
Item = Workers(Index)
End Property
Public Property Set Item(Index As Integer, Value As Variant)
Workers.Remove Index
Workers.add Value, Before:=Index
End Property
with hidden attributes Attribute Item.VB_UserMemId = 0 at Getter and Setter.
Getting works fine:
Dim wks As New Workers
wks.add "Worker1"
wks.add "Worker2"
wks.add "Worker3"
Debug.Print wks(2) ' <-- OK here
'wks(2) = "Second Worker" ' <-- By debugging this go to Getter not Setter and after Getter is done, it allerts with Runtime error '424': Object required
Set wks(2) = "Second Worker" ' <-- This alert immediately Compile error: Object required on "Second Worker" string
Debug.Print wks(2)
Prints "Worker2" into console, thanks for this, but still I'm not able to set a new value to the required Index of the Workers Collection.
You could use a default member in VBA. Though you can't make the default memeber directly through VBA editor, but you can use any text editor.
Export your class from VBA editor, i.e. File->Export File
Open your exported class in Notepad (or any text editor)
Add this attribute line on your method or property you want to make it default. Attribute Item.VB_UserMemId = 0
You can for example make getWorker default member as.
Public Function GetWorker(Index As Integer) As Worker
Attribute Item.VB_UserMemId = 0
GetWorker = Workers(Index)
End Function
you can then use it like.
Set wk = wks(1)
Here is some detail about default members
http://www.cpearson.com/excel/DefaultMember.aspx
Edits
An example to make Getter/Setter as default member
Public Property Get Item(Index as Integer) as Worker
Attribute Item.VB_UserMemId = 0
Set Item = Workers(Index)
End Property
Public Property Set Item(Index as Integer, Value as Worker)
Attribute Item.VB_UserMemId = 0
Set Workers(Index) = Value
End Property

Nested custom collection class | Runtime error 91 object variable or with block variable not set

I have the following custom class LinkEnd, where Portal is another custom class I created:
Option Explicit
Private ePortal As Portal
Private eHeading As Double
Public Property Get Portal() As Portal
Portal = ePortal
End Property
Public Property Let Portal(Value As Portal)
ePortal = Value
End Property
Public Property Get Heading() As Double
Heading = eHeading
End Property
Public Property Let Heading(Value As Double)
eHeading = Value
End Property
I am using the LinkEnds in the class Link:
Option Explicit
Private LinkEnds As New Collection
Public Sub Add(p As Portal)
Dim NewLinkEnd As New LinkEnd
With NewLinkEnd
.Portal = p
End With
LinkEnds.Add NewLinkEnd
End Sub
I checked; the NewLinkEnd is defined fine; the problem is with the line
.Portal = p
How do I correctly assign the Portal inside the NewLinkEnd? I used almost identical code for a Custom Collection Class Portals which is a Collection of Portal objects, and it works fine there...

VBA: instantiate class A in a property of class B

I am a beginner at excel VBA OOP and need help putting a class instance with a property into the property of another class. I have a way which makes sense to me but does not work. I'm not sure if its just a simply syntax/structure error, or if I'm missing the mark on this entirely. Here is a simplified example which illustrates my problem:
Class A has a property with a string value.
Class B has a property that holds an instance of Class A, and this property takes a string parameter and passes it to Class A's property.
Class A
Private strProp As String
Public Property Let Prop(sProp As String)
strProp = sProp
End Property
Class B
Private clsA As New ClassA
'''DIFFERENT ATTEMPTS OF THE SAME METHOD:
Public Property Let ClassA(strNameA As String)
clsA.Prop = strNameA
End Property
'Public Property Set ClassA(strNameA As String)
' clsA.Prop = strNameA
'End Property
'Public Property Set ClassA(strNameA As String)
'
' Dim xClsA As ClassA
' Set xClsA = New ClassA
'
' xClsA.name = "Foobar"
' clsA = xClsA
'
'End Property
'
Public Function message()
msgbox(clsA.Prop)
End Function
Module (the classes in action)
dim xClassB as ClassB
set xClassB = new ClassB
xClassB.ClassA("Foobar")
xClassB.message 'should display Foobar
the error I get:
"I still get a compile error: definitions of property procedure for the same property are inconsistent or property procedure has an optional parameter, a ParaArray, or an invalid set final parameter"
Class A
Private strProp As String
Public Property Let Prop(sProp As String)
strProp = sProp
End Property
Public Property Get Prop() As String
Prop = strProp
End Property
ClassB:
Private clsA As New ClassA
Public Property Set ClassA(strNameA As String)
clsA.Prop = strNameA
End Property
Public Function message()
msgbox(clsA.Prop)
End Function
...and add a Get for Prop in ClassA

PostSharp -- Apply attribute to all private fields

I would like to apply an attribute, (e.g. <DebuggerBrowsable(DebuggerBrowsableState.Never)>) to all private fields in a class.
How can I accomplish this with PostSharp?
I have tried applying the following aspect to the classes, but without success.
<MulticastAttributeUsage(MulticastTargets.Class)>
<Serializable>
Public Class DebuggerBrowsableHidePrivateMembersAttribute
Inherits TypeLevelAspect
Implements IAspectProvider
Public Iterator Function ProvideAspects(targetElement As Object) As IEnumerable(Of AspectInstance) Implements IAspectProvider.ProvideAspects
Dim targetType = targetElement.GetType
Dim aspect = New CustomAttributeIntroductionAspect(New ObjectConstruction(targetType, DebuggerBrowsableState.Never))
For Each field In targetType.GetFields(BindingFlags.NonPublic Or BindingFlags.DeclaredOnly)
Yield New AspectInstance(field, aspect)
Next
End Function
End Class
I ended up using the following aspect:
Imports PostSharp.Aspects
Imports PostSharp.Extensibility
Imports PostSharp.Reflection
<MulticastAttributeUsage(MulticastTargets.Field Or MulticastTargets.Property)>
Public NotInheritable Class DebuggerBrowsableHideMembersAttribute
Inherits LocationLevelAspect
Implements IAspectProvider
'Hides the following members from browsable debugger windows.
' Private Fields
' Protected Fields
' Static (Shared) Fields
' Private Properties
' Protected Properties
' Static (Shared) Properties
' Indexed Properties
Private Shared ReadOnly Aspect As New CustomAttributeIntroductionAspect(New ObjectConstruction(GetType(DebuggerBrowsableAttribute), DebuggerBrowsableState.Never))
Public Iterator Function ProvideAspects(targetElement As Object) As IEnumerable(Of AspectInstance) Implements IAspectProvider.ProvideAspects
Dim location = DirectCast(targetElement, LocationInfo)
Select Case location.LocationKind
Case LocationKind.Field
Dim info = location.FieldInfo
If info.IsPrivate OrElse info.IsFamily OrElse info.IsStatic Then
Yield New AspectInstance(location.FieldInfo, Aspect)
End If
Case LocationKind.Property
Dim info = location.PropertyInfo.GetMethod
If info.IsPrivate OrElse info.IsFamily OrElse info.IsStatic OrElse info.GetParameters.Count > 0 Then
Yield New AspectInstance(location.PropertyInfo, Aspect)
End If
End Select
Exit Function
End Function
End Class

Resources