Is it possible to get object instance member? - vb.net

I trying to get member name and it attribute. I used StackTrace, GetType(), MemberInfo etc but with no luck.
Class Test
Class Test
<Description("Some description")> Property TestProperty1 As Test2
<Description("Some description")> Property TestProperty2 As Test2
Sub New()
TestProperty1 = New Test2("Test text")
TestProperty2 = New Test2("")
End Sub
End Class
End Class
Class Test2
Property Text As String
Sub New(ByVal SomeText As String)
Text = SomeText
End Sub
End Class
<AttributeUsage(AttributeTargets.Property, Inherited:=False)>
Class Description : Inherits Attribute
Property Description As String
Sub New(ByVal Value As String)
Description = Value
End Sub
End Class
I can get invocation method (caller member), Source class TypeInfo and its members but I can't determine what kind exactly member is true instance of my class.
Is there way to get member name "TestProperty1" of class "Test" from Sub New(ByVal SomeText As String) of class "Test2"?

Related

User Defined Class using Implements: how to put common implemented code in one place [duplicate]

This question already has an answer here:
VBA inheritance pattern
(1 answer)
Closed 4 months ago.
I’m creating a set of User Defined Classes using Implements. Some (but not all) of the Properties and Methods of the implemented classes use exactly the same code in each implemented class. What I would like to do is move that code to one place, to avoid repeating myself.
An minimal example to demonstrate the requirement:
Class cMasterClass
Option Explicit
Private pMyClasses As Collection
Public Property Get Item(idx As Long)
Set Item = pMyClasses.Item(idx)
End Property
Public Property Get SomeProperty() As String
SomeProperty = "Master Class"
End Property
Public Sub AddClass(Name As String, Instance As Long)
Dim NewClass As cTemplateClass
Select Case Instance
Case 1
Set NewClass = New cMyClass1
Case 2
Set NewClass = New cMyClass2
End Select
NewClass.Init Me, Name
pMyClasses.Add NewClass, Name
End Sub
Private Sub Class_Initialize()
Set pMyClasses = New Collection
End Sub
Class cTemplateClass
Option Explicit
Public Property Get Name() As String: End Property
Public Property Get Parent() As cMasterClass: End Property
Public Property Get SomeProperty() As String: End Property
Public Sub Init(Parent As cMasterClass, Name As String): End Sub
Class cMyClass1
Option Explicit
Implements cTemplateClass
Private pParent As cMasterClass
Private pName As String
Public Property Get cTemplateClass_Name() As String: cTemplateClass_Name = pName: End Property
Public Property Get cTemplateClass_Parent() As cMasterClass: Set cTemplateClass_Parent = pParent: End Property
Public Property Get cTemplateClass_SomeProperty() As String
cTemplateClass_SomeProperty = "Some String from MyClass 1"
End Property
Public Sub cTemplateClass_Init(Parent As cMasterClass, Name As String)
Set pParent = Parent
pName = Name
End Sub
Class cMyClass2
Option Explicit
Implements cTemplateClass
Private pParent As cMasterClass
Private pName As String
Public Property Get cTemplateClass_Name() As String: cTemplateClass_Name = pName: End Property
Public Property Get cTemplateClass_Parent() As cMasterClass: Set cTemplateClass_Parent = pParent: End Property
Public Property Get cTemplateClass_SomeProperty() As String
cTemplateClass_SomeProperty = "Some String from MyClass 2"
End Property
Public Sub cTemplateClass_Init(Parent As cMasterClass, Name As String)
Set pParent = Parent
pName = Name
End Sub
Standard Module
Sub Demo()
Dim MyMasterClass As cMasterClass
Set MyMasterClass = New cMasterClass
MyMasterClass.AddClass "Example class 1", 1
MyMasterClass.AddClass "Example class 2", 2
Dim SomeInstance As cTemplateClass
Set SomeInstance = MyMasterClass.Item(1)
Debug.Print "Instance 1", SomeInstance.Name, "Parent", SomeInstance.Parent.SomeProperty
Set SomeInstance = MyMasterClass.Item(2)
Debug.Print "Instance 2", SomeInstance.Name, "Parent", SomeInstance.Parent.SomeProperty
End Sub
Notice that in cMyClass1 and cMyClass2 the code for Init, Name and Parent are identical (but SomeProperty is not)
How could I move the common code from the individual classes into one place (I know the Template class cannot contain the common code)?
How could I move the common code from the individual classes into one place (I know the Template class cannot contain the common code)?
Hi Chris, actually the Template class can contain that common code and be used with Implements to ensure that interface implementation. I am late with this answer and I am not sure if this can help you but anyway ... :). What you could consider would be to actually move the parent and name to your template class and use init to fill them and at the same time with using implements create instance of the template so your classes ensure that interface and they can redirect the code to the template at the same time. If you wish have a look here for another example. HTH, Dan
Change the child classes a bit:
Option Explicit
Implements cTemplateClass
'Move this to your template class:
'Private pParent As cMasterClass
'Private pName As String
'and declare the varaible of template class here instead:
Private pTemplate As cTemplateClass
Public Property Get cTemplateClass_Name() As String
'Redirect the property to template class instance
'cTemplateClass_Name = pName
cTemplateClass_Name = pTemplate.Name
End Property
Public Property Get cTemplateClass_Parent() As cMasterClass
'Redirect the property to template class instance
'Set cTemplateClass_Parent = pParent
Set cTemplateClass_Parent = pTemplate.Parent
End Property
Public Sub cTemplateClass_Init(Parent As cMasterClass, Name As String)
' Instantiate here the template class and redirect the Init
' Set pParent = Parent
' pName = Name
Set pTemplate = New cTemplateClass
pTemplate.Init Parent, Name
End Sub
Public Property Get cTemplateClass_SomeProperty() As String
cTemplateClass_SomeProperty = "Some String from MyClass 2"
End Property
And anhance the template class a bit too:
Option Explicit
'Move this here from your 'derived' classes:
Private pParent As cMasterClass
Private pName As String
Public Property Get Name() As String
Name = pName
End Property
Public Property Get Parent() As cMasterClass
Set Parent = pParent
End Property
Public Sub Init(Parent As cMasterClass, Name As String)
Set pParent = Parent
pName = Name
End Sub
Public Property Get SomeProperty() As String
End Property

Getting a property from the instantiator class

Not an experienced programmer, so probably not a hard question.
Developing a small application in VB.net in WPF.
I made 3 classes, EngineeringObject<==Inherits==PartOfInstallation<==Inherits==SensorActor
In the class SensorActor I'm trying to get a property of PartOfInstallation with the function MyBase.Name. But this goes directly to EngineeringObject. How do I solve this?
Public Class EngineeringObject
''Private declarations, alleen objecten die erven kunnen hieraan, of dmv van getters en setters
'Name of part
Private sName As String = "Naam"
'81346 Id's
Private sSystemId As String = "Functie" 'VentilationSystem, Pumpsystem
Private sLocationId As String = "Locatie" 'Room 0.0
Private sObjectId As String = "Object" 'Fan, Pump
'General
Private sPartNumber As String
Private sLinkToDatasheet As String
'Property's
Public Property Name() As String
Get
Return sName
End Get
Set(ByVal value As String)
sName = value
End Set
End Property
Public Property SystemId() As String
Get
Return sSystemId
End Get
Set(ByVal value As String)
sSystemId = value
End Set
End Property
Public Property PartNumber() As String
Get
Return sPartNumber
End Get
Set(ByVal value As String)
sPartNumber = value
End Set
End Property
Public Property LinkToDatasheet() As String
Get
Return sLinkToDatasheet
End Get
Set(ByVal value As String)
sLinkToDatasheet = value
End Set
End Property
Public Sub New()
End Sub
End Class
Public Class PartOfInstallation
Inherits EngineeringObject
'src: https://stackoverflow.com/questions/21308881/parent-creating-child-object
'src: https://stackoverflow.com/questions/16244548/how-to-create-a-list-of-parent-objects-where-each-parent-can-have-a-list-of-chil
Private lSensorActor As New List(Of SensorActor)
Public Function GetSensorActor()
Return Me.lSensorActor
End Function
Public Sub CreateSensorActor()
lSensorActor.Add(New SensorActor)
End Sub
End Class
Public Class SensorActor
Inherits PartOfInstallation
Dim sMyPartOfInstallation As String
Public Property MyPartOfInstallation As String
Get
Return sMyPartOfInstallation
End Get
Set(value As String)
sMyPartOfInstallation = MyBase.Name
End Set
End Property
End Class
If I understand it correctly, based on your comments, you want every SensorActor instantiated within a PartOfInstallation instance to get the same name as that instance.
If so, then just add a second constructor to your SensorActor class allowing you to pass a name for it as well:
Public Class SensorActor
Inherits PartOfInstallation
...your code...
Public Sub New() 'Empty constructor, for if/when you don't want to set the name immediately.
End Sub
Public Sub New(ByVal Name As String)
Me.Name = Name
End Sub
End Class
Now in your PartOfInstallation class you can do:
Public Sub CreateSensorActor()
lSensorActor.Add(New SensorActor(Me.Name)) 'Here, "Me" refers to the current PartOfInstallation instance.
End Sub
Alternatively you can make the SensorActor constructor take a PartOfInstallation instance instead, allowing you to copy any properties you like:
Public Class SensorActor
Inherits PartOfInstallation
...your code...
Public Sub New()
End Sub
Public Sub New(ByVal BasedOnPOI As PartOfInstallation)
Me.Name = BasedOnPOI.Name
End Sub
End Class
Thus making the code in the PartOfInstallation class:
Public Sub CreateSensorActor()
lSensorActor.Add(New SensorActor(Me))
End Sub
Read more about constructors: Object Lifetime: How Objects Are Created and Destroyed (Visual Basic) | Microsoft Docs
The result below, if there's room for improvement... always welcome.
SensorActor
Public Class SensorActor
Inherits PartOfInstallation
Dim sTemp As String
Public Overloads Property SystemId() As String
Get
Return Me.sSystemId
End Get
Set(ByVal value As String)
Me.sSystemId = sTemp + "." + value
End Set
End Property
Public Sub New(ByVal BasedOnPOI As PartOfInstallation)
sTemp = BasedOnPOI.SystemId
End Sub
End Class
PartOfInstallation
Public Class PartOfInstallation
Inherits EngineeringObject
'src: https://stackoverflow.com/questions/21308881/parent-creating-child-object
'src: https://stackoverflow.com/questions/16244548/how-to-create-a-list-of-parent-objects-where-each-parent-can-have-a-list-of-chil
Private lSensorActor As New List(Of SensorActor)
Public Function GetSensorActor()
Return Me.lSensorActor
End Function
Public Sub CreateSensorActor()
lSensorActor.Add(New SensorActor(Me))
End Sub
End Class
EngineeringObject
Public Class EngineeringObject
''Private declarations, alleen objecten die erven kunnen hieraan, of dmv van getters en setters
'Name of part
Private sName As String = "Naam"
'81346 Id's
Friend sSystemId As String = "Functie" 'VentilationSystem, Pumpsystem
Private sLocationId As String = "Locatie" 'Room 0.0
Private sObjectId As String = "Object" 'Fan, Pump
'General
Private sPartNumber As String
Private sLinkToDatasheet As String
'Property's
Public Property Name() As String
Get
Return sName
End Get
Set(ByVal value As String)
sName = value
End Set
End Property
Public Property SystemId() As String
Get
Return sSystemId
End Get
Set(ByVal value As String)
sSystemId = "=" + value
End Set
End Property
Public Property PartNumber() As String
Get
Return sPartNumber
End Get
Set(ByVal value As String)
sPartNumber = value
End Set
End Property
Public Property LinkToDatasheet() As String
Get
Return sLinkToDatasheet
End Get
Set(ByVal value As String)
sLinkToDatasheet = value
End Set
End Property
Public Sub New()
End Sub
End Class

Issue when implementing getter and setter from an interface

I have a class which implements another object. I set a property function for each property of the implemented object but keep getting an 'Invalid use of property' error. Here's my code:
Test Sub:
Sub tst()
Dim a As Derived
Set a = New Derived
a.Base_name = "ALGO" 'Error happens when this executes
End Sub
Derived class module:
Option Explicit
Implements Base
Private sec As Base
Private Sub Class_Initialize()
Set sec = New Base
End Sub
Public Property Get Base_name() As String
Call sec.name
End Property
Public Property Let Base_name(value As String)
Call sec.name(value) 'Error happens here
End Property
Base Class module:
Private pname As String
Public Property Get name() As String
name = pname
End Property
Public Property Let name(value As String)
pname = value
End Property
Is this what you want?
Module1
Sub tst()
Dim a As Derived
Set a = New Derived
Debug.Print a.Base_name
a.Base_name = "ALGO"
Debug.Print a.Base_name
End Sub
Base Class Module
Private pname As String
Public Property Get name() As String
name = pname
End Property
Public Property Let name(value As String)
pname = value
End Property
Derived Class Module
Option Explicit
Implements Base
Private sec As Base
Private Sub Class_Initialize()
Set sec = New Base
End Sub
Public Property Get Base_name() As String
Base_name = sec.name
End Property
Public Property Let Base_name(value As String)
sec.name = value
End Property

how to access class from inherited class

I have two classes:
class class2
inherits class1
public sub modify()
'modify property of class1
end sub
end class
How can I modify class1 in a sub in class2?
You just call it. Example:
Public Class class1
Private _Value As String = String.Empty
Property Value() As String
Get
Return _Value
End Get
Set(ByVal value As String)
_Value = value
End Set
End Property
End Class
Public Class class2
Inherits class1
Public Sub modify()
Value = "modified"
End Sub
End Class
And to show it works:
Dim c2 As New class2
c2.modify()
MessageBox.Show(c2.Value)
You are asking about properties, note that only protected and public properties are visible to inherited classes.
You need the MyBase keyword when you are overriding an existing function in the parent class. Other protected or public properties or functions can be accessed regulary without any special keyword.
One tip I wanted to add to the above comments regarding accessing base class info is where you have a base class without a default contructor or want to use a specific constructor This is a good opportunity to use Mybase. You have to call the constructor before any additional actions take place in this scenario.
Public Class MyClass
Inherits baseClass
Public Sub New()
mybase.new("Oranges")
End Sub
End Class
Public Class baseClass
Private _someVariable as String
Public Sub New(byval passedString as string)
_someVariable = passedString
End Sub
End Class

Can't create a Collection of Inherited Classes

Maybe I just don't know what to search for, but I'm going a little bonkers here trying to figure out how to create a collection of inherited classes. The base class, I will never use.
Basically, I have 3 components:
A base class call ImageFormat
Child classes of ImageForm
Code in Sub Main() to loop create a
collection and loop through it.
So it does it, #3. The problem is that it always gets the last item added to the collection and uses it's values only.
Here's my Base Class:
Public MustInherit Class ImageFormat
Protected Shared _extentions As String()
Protected Shared _targettype As String
Protected Shared _name As String
Public ReadOnly Property Extentions As String()
Get
Return _extentions
End Get
End Property
Public ReadOnly Property TargetType As String
Get
Return _targettype
End Get
End Property
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
End Class
And here are the child classes:
Class WindowsEnhancedMetafile
Inherits ImageFormat
Sub New()
_extentions = {"EMF"}
_targettype = "jpg"
_name = "Windows Enhanced Metafile"
End Sub
End Class
Class WindowsBitmap
Inherits ImageFormat
Sub New()
_extentions = {"BMP", "DIB", "RLE", "BMZ"}
_targettype = "jpg"
_name = "Windows Bitmap"
End Sub
End Class
Class WindowsMetafile
Inherits ImageFormat
Sub New()
_extentions = {"WMF"}
_targettype = "jpg"
_name = "Windows Metafile"
End Sub
End Class
(don't know if these child classes need to different, like just instantied from ImageFormat type or Singleton patterns - would appreciate anything thoughts you have on this)
Then, my routine is:
Sub Main()
Dim imgFormats As New List(Of ImageFormat)
imgFormats.Add(New WindowsBitmap)
imgFormats.Add(New WindowsMetafile)
imgFormats.Add(New WindowsEnhancedMetafile)
Dim name As String = String.Empty
For Each imgFormat In imgFormats
name = imgFormat.Name
Console.WriteLine(name)
Next
Console.ReadLine()
End Sub
This returns Windows Enhanced Metafile three times at the Console. What am I doing wrong here?
The three properties:
Protected Shared _extentions As String()
Protected Shared _targettype As String
Protected Shared _name As String
Are marked as Shared - they belong to the class not the object.
Each time you assign a new value to _name it overrides the old value, thus why you get the same name printed each time.
It should be:
Protected _extentions As String()
Protected _targettype As String
Protected _name As String
Well, your _name et al are Shared, which means they are class-level variables. When you're adding WindowsEnhancedMetafile, it happens to overwrite these fields with WMF-specific information. If you changed your code to:
imgFormats.Add(New WindowsMetafile)
imgFormats.Add(New WindowsEnhancedMetafile)
imgFormats.Add(New WindowsBitmap)
you would've had "Windows Bitmap" printed three times.
All you have to do is to change your field declarations to
Protected _extentions As String()
Protected _targettype As String
Protected _name As String