Can't iterate through each property of a custom object - vb.net

I have this class:
Public Class clsServCasam
Public ID As Long
Public CANT As Decimal
Public PRICE As Decimal
End Class
I create a variable of that type and get the object from an API result:
Dim myObj As clsServCasam()
Dim rsp As HttpWebResponse = CType(rq.GetResponse(), HttpWebResponse)
If rsp.StatusCode = HttpStatusCode.OK Then
Using sr = New StreamReader(rsp.GetResponseStream())
myObj = JsonConvert.DeserializeObject(Of clsServCasam())(sr.ReadToEnd())
End Using
Then I try to get the field names from the object:
For Each p As System.Reflection.PropertyInfo In myObj.GetType().GetProperties()
Debug.Print(p.Name, p.GetValue(myObj, Nothing))
Next
But, instead of class fields (ID, PRICE, ...) I got:
- Length
- LongLength
- Rank
Update
As Steven Doggart pointed out, the above loop won't work because it looks for properties rather than fields. So, I tried changing the loop to this:
For Each p As FieldInfo In myObj.GetType.GetFields()
Debug.Print(p.Name)
Next
But now I'm getting no results at all.

In your code, myObj is not declared as clsServCasam. Rather, it is declared as clsServCasam(), which means it's an array of clsServCasam objects. So, when you use reflection to iterate over its properties, you're getting the properties of the array rather than the actual clsServCasam type.
For instance, this would work more like you're expecting:
For Each item As clsServCasam in myObj
For Each p As PropertyInfo In item.GetType().GetProperties()
Debug.Print(p.Name, p.GetValue(item, Nothing))
Next
Next
However, I think you'll find that that still won't work because it iterates over the properties rather than the fields. In the definition of the clsServCasam class, all of the members are fields rather than properties, so the only properties that it have would be ones that are inherited from Object. You will need to either iterate over the fields using GetFields, like this:
For Each item As clsServCasam in myObj
For Each f As FieldInfo In item.GetType().GetFields()
Debug.Print(f.Name, f.GetValue(item))
Next
Next
Or you'll need to change them to properties:
Public Class clsServCasam
Public Property ID As Long
Public Property CANT As Decimal
Public Property PRICE As Decimal
End Class
Or, if you are using an older version of the VB compiler which doesn't support auto-properties:
Public Class clsServCasam
Public Property ID As Long
Get
Return _id
End Get
Set(value As Long)
_id = value
End Set
End Property
Public Property CANT As Decimal
Get
Return _cant
End Get
Set(value As Decimal)
_cant = value
End Set
End Property
Public Property PRICE As Decimal
Get
Return _price
End Get
Set(value As Decimal)
_price = value
End Set
End Property
Private _id As Long
Private _cant As Decimal
Private _price As Decimal
End Class

Related

Predefined class properties if need expand or shrink quantity of them on each app start

Public Class Products
Private zCriteria As String
Public Property Criteria As String
Get
Return zCriteria
End Get
Set(value As String)
zCriteria = value
End Set
End Property
Private zProductList As New List(Of Product)
Public Property ProductList As List(Of Product)
Get
Return zProductList
End Get
Set(value As List(Of Product))
zProductList = value
End Set
End Property
End Class
Public Class Product
Private zCriteriaList As List(Of Criterias)
Public Property CriteriaList As List(Of Criterias)
Get
Return zCriteriaList
End Get
Set(value As List(Of Criterias))
zCriteriaList = value
End Set
End Property
End Class
Public Class Criterias
Private zCrPropName As String
Public Property CrPropName As String
Get
Return zCrPropName
End Get
Set(value As String)
zCrPropName = value
End Set
End Property
Private zCritCode As String
Public Property CritCode As String
Get
Return zCritCode
End Get
Set(value As String)
zCritCode = value
End Set
End Property
Private zcrPropValue As String
Public Property crPropValue As String
Get
Return zcrPropValue
End Get
Set(value As String)
zcrPropValue = value
End Set
End Property
End Class
For Each oProducts As Products In oAssigment.ProductsList
For Each oproduct As Product In oProducts.ProductList
For Each cr As Criterias In oproduct.CriteriaList
cr.CrPropName = "Product Name" 'some object property name
cr.CritCode = "PN"
cr.crPropValue = "" ' Value of property "Product Name"
Next
Next
Next
It is all made to have different properties of some object depending on options set in text file. It is only a sample o usage.
conditions:
Criterias on applications start is same for all objects (=Product) i want to read.
Every time on start, application read options file where is defined few property names and codes (values i want get from objects). So every run can be initiated different quantity of properties to read. It means i can not have hard-coded names of properties.
Someone can advice me how to predefine "CrPropName" and "CritCode" on app start so many times how much property names defined in options and after that populate it so many times as how many objects exist from which i read these property values.
p.s. I am not very professional at coding and sorry for my language

For a combobox with item = a datarow, how to point ValueMember to one of it's columns

I add items to a combobox like this:
For each R as DataRow in MyDataTable.Rows
If R("ID") > 10 then MyCombo.Items.Add(R)
Next
And now I need to set the DisplayMember and ValueMember to a column of the datarow:
MyCombo.ValueMember = R("ID")
MyCombo.DisplayMember = R("Name")
I know it doesn't make sence to to use "R" as it doesn't reference to anything at this point but it's just to make an indication of what I mean ;-)
The documentation for ValueMember says:
"A String representing a single property name of the DataSource property value, or a hierarchy of period-delimited property names that resolves to a property name of the final data-bound object"
I know I can add the rows to a new datatable and set it to the DataSource, but as you can add any object to the combobox items, it would be nice to use the rows directly, just can't figures out how to make a reference the particular column as a string.?
Maybe you cannot use a row object directly. I guess to use Valuemember you need your item objects to be wrapped in a collection which implement an ilist interface.
In the old MS-Access days combobox items had natively Display- and ValueMember properties, I've always missed that in the .Net combobox control.
My work-around is to use this class, which then can be used for all your ComboBoxes:
Class oComboItems
Public items As New List(Of oDVpairs)
Class oDVpairs
Implements IComparable(Of oDVpairs)
Private myDM As String
Private myVM As Object
Sub New(DM As String, VM As Object)
myDM = DM
myVM = VM
End Sub
Public ReadOnly Property DM() As String
Get
Return myDM
End Get
End Property
Public ReadOnly Property VM() As Object
Get
Return myVM
End Get
End Property
Public Function CompareTo(other As oDVpairs) As Integer Implements IComparable(Of oDVpairs).CompareTo
Return Me.myDM.CompareTo(other.myDM)
End Function
End Class
Public Sub AddItems(DisplayMember As String, ValueMemeber As Object)
items.Add(New oDVpairs(DisplayMember, ValueMemeber))
End Sub
Public ReadOnly Property DisplayMember() As String
Get
Return "DM"
End Get
End Property
Public ReadOnly Property ValueMember() As Object
Get
Return "VM"
End Get
End Property
End Class
And now add my datarows(or any other objects) to the ComboBox:
Dim CI As New oComboItems
For Each R As DataRow In DT_U.Rows
If R("medlnr") > 10 Then
CI.AddItems(R("name"), R("ID"))
end if
Next
CI.items.Sort()
MyCombo.DataSource = CI.Items
MyCombo.DisplayMember = CI.DisplayMember
MyCombo.ValueMember = CI.ValueMember

Convert a Variable To a Propery Variable Using Reflection

I am trying to convert
Public Class TestClass
Public FirstName As String
End Class
To
Public Class AnotherClass
Public Property FirstName As String
End Class
I wrote a function that will convert the member of one class to member of another class, so if I pass some class type that has Public Property LastName AS String it will convert it to (for instance) AnotherClass Type variable and I will be able to get the value so I am happy here.
Public Shared Function ConvertModelToValidationDataModel(Of T)(ByVal oSourceObject As Object) As T
Dim oSourceObjectType As Type
Dim oSourceObjectProperties() As PropertyInfo
Dim oDestinationObjectProperties() As PropertyInfo
Dim oDestinationObject As Object
Dim oDestinationObjectType As Type
oDestinationObject = Activator.CreateInstance(Of T)()
oDestinationObjectType = GetType(T)
oDestinationObjectProperties = oDestinationObjectType.GetProperties
oSourceObjectType = oSourceObject.GetType()
oSourceObjectProperties = oSourceObjectType.GetProperties()
If Not oSourceObjectProperties Is Nothing Then
If oSourceObjectProperties.Count > 0 Then
For Each oDestinationObjectPropertyInfo As PropertyInfo In oDestinationObjectProperties
For Each oSourceObjectPropertyInfo As PropertyInfo In oSourceObjectProperties
If oDestinationObjectPropertyInfo.Name = oSourceObjectPropertyInfo.Name Then
oDestinationObjectPropertyInfo.SetValue(oDestinationObject, oSourceObjectPropertyInfo.GetValue(oSourceObject, Nothing))
End If
Next
Next
End If
End If
Return oDestinationObject
End Function
The problem is I want to pass TestClass (the variable FirstName is not a property but I want it to be converted to a property variable) and be able to convert it and get the value but for some reason it does not pass the value and obviously it looks like the function converts it to a non-property variable of another class - not the property variable like I want it to.
**
Short version:
**
When I pass in a class type that has property variables (Public Property FirstName As String) - I get back a class of another type, all the values are passed and converted to property variables.
When I pass in class type that has variables (Public FirstName As String) I am not able to get the value and it does not convert it to property variable.
Question: Why I am not able to get the value and convert it to a property variable when passing in a class type that has a non-property variable?
Solution
Thanks the guys in the comment section below for helping me visualize the fact that I was asking an object for the properties while object only had fields.
Here is the Updated Version of the function for those who interested
Public Shared Function ConvertModelToValidationDataModel(Of T)(ByVal oSourceObject As Object) As T
Dim oSourceObjectType As Type
Dim oSourceObjectFields() As FieldInfo
Dim oDestinationObjectProperties() As PropertyInfo
Dim oDestinationObject As Object
Dim oDestinationObjectType As Type
oSourceObjectType = oSourceObject.GetType()
oSourceObjectFields = oSourceObjectType.GetFields()
oDestinationObject = Activator.CreateInstance(Of T)()
oDestinationObjectType = GetType(T)
oDestinationObjectProperties = oDestinationObjectType.GetProperties
If Not oSourceObjectFields Is Nothing Then
If oSourceObjectFields.Count > 0 Then
For Each oSourceObjectFieldInfo As FieldInfo In oSourceObjectFields
For Each oDestinationObjectPropertyInfo As PropertyInfo In oDestinationObjectProperties
If oSourceObjectFieldInfo.Name = oDestinationObjectPropertyInfo.Name Then
oDestinationObjectPropertyInfo.SetValue(oDestinationObject, oSourceObjectFieldInfo.GetValue(oSourceObject))
End If
Next
Next
End If
End If
Return oDestinationObject
End Function

How to use instance of New Object in With... Block

Dim objects As New List(Of Object)
With New Object
.prop1 = "Property 1"
.prop2 = "Property 2"
objects.add(.instance) 'i mean instance of New Object
End With
is it possible.
I ask new question because last question has mislead information and I don't give right answer. so here code.
No it is not possible. The With statement basically creates an implicit variable. All you can do with that variable is access members and there is no member that returns a reference to the object itself.
If you want succinct code to create, populate and add an object to a list then do this:
myList.Add(New SomeType With {.SomeProperty = someValue,
.SomeOtherProperty = someOtherValue})
Interestingly, you can make it work the way you wanted if you create your own extension method. I was under the impression that you could not extend the Object class but either I was wrong or that has changed because I just tried in VB 2013 and it worked. You can write a method like this:
Imports System.Runtime.CompilerServices
Public Module ObjectExtensions
<Extension>
Public Function Self(Of T)(source As T) As T
Return source
End Function
End Module
and then do something like this:
With New SomeType
.SomeProperty = someValue
.SomeOtherProperty = someOtherValue
myList.Add(.Self())
End With
I'm not sure that that really provides any benefit though, given the availability of the object initialiser syntax that I demonstrated first.
Hmmm... I just realised that that's not actually extending the Object class. It was my original intention to try to do so but then I realised that a generic method was better because it would then return the same type as you call it on. I did just test it with a non-generic method extending type Object and it did still worked though.
You should to create your own class By example :
Public Class Car
Private _NumberCar As Integer
Public Property NumberCar() As Integer
Get
Return _NumberCar
End Get
Set(ByVal value As Integer)
_NumberCar = value
End Set
End Property
Private _ColorCar As Color
Public Property ColorCar() As Color
Get
Return _ColorCar
End Get
Set(ByVal value As Color)
_ColorCar = value
End Set
End Property
Private _OwnerName As String
Public Property OwnerName() As String
Get
Return _OwnerName
End Get
Set(ByVal value As String)
_OwnerName = value
End Set
End Property
End Class
and in the Class where you want to add the cars object do this :
Dim CarList As New List(Of Car)
Dim item As New Car
With item
.NumberCar = 1243
.ColorCar = Color.Red
.OwnerName = "Ibra"
End With
CarList.Add(item)
strong text

Returning Class Object from Inherited class

I'm trying to teach myself reflection and have been googling but I can't wrap my head around it entirely. I created a class called DataClass which contains a method called GetClassFromDB as you can see below, which will be inherited from multiple classes.
What I am attempting to do is have my dataclass read the TableName property that is defined within objResults. Once I pull in the tablename from objResults I would query the SQL database for a dataset. Once I have the dataset I would create a new object of the same TYPE inheriting this class (Which will be different types) and populate it from the dataset. Once I have the newly populated class I will return it for use.
I believe I have gotten most of the way there properly (Please correct me if there is a better way), but my real question is this. How can I create a new class of the type thats deriving that class from that string name that I getting in my code, or the type. I would want to have all the accessible properties from objResults available.
Namespace MyApp
Public Class DataClass
Private _TableName As String
Private _Name As String
Overridable ReadOnly Property TableName As String
Get
Return _TableName
End Get
End Property
Public Overloads Function GetClassFromDB() As Object
Try
Dim BaseObject As New Object
'Get the object name
Dim objName As String = MyBase.GetType().Name
'Gets the type thats calling this method
Dim objDerived As Type = MyBase.GetType()
'Get the property info to request the tablename from the derived class
Dim TableName As PropertyInfo = objDerived.GetProperty("TableName")
Dim TableNameString As String = TableName.GetValue(Me, Nothing).ToString
'Once I get the table name from objResults I can perform the SQL
Dim QueryResults as DataSet = SQLiteCLass.Query("Select * FROM TableNameString")
'Once I get data from the SQL I want to create a new object of the type deriving this method.
'In this example is objResults
Dim NewObject as objDerived
'Now I can fill my new object with the results and return it as an object
'THIS IS MY QUESTION - How can I create a new object of the TYPE that I receive from Reflection
Return False
Catch ex As Exception
Return False
End Try
End Function
End Class
End Namespace
and this is a sample class that would inherit my dataclass.
Public Class objResults
Inherits MyApp.DataClass
Private _GameID As Guid
Public Property GameID As Guid
Get
Return _GameID
End Get
Set(ByVal value As Guid)
_GameID = value
End Set
End Property
Public Overrides ReadOnly Property TableName As String
Get
Return "This is my tablename"
End Get
End Property
End Class
and this is how I would use this in code.
Dim objResult as New objResults
Dim TodaysResult as objResultsCollection
TodaysResult = objResult.GetClassFromDB()