Using Type Class

G

Guest

I have a class named "myclass" and an arraylist containing elements of type
"MyClass". I want to get the value of a property of "MyClass" (a string
type) for one of the arraylist elements.

I can get this using:
dim b as string
b = DirectCast(myarraylist(0),myclass).myproperty

However, I want to use an object to define the type "MyClass" like:
dim C as type = type.GetType(myarraylist(0))
b = DirectCast(myarraylist(0), C ).MyProperty

but I get a "c" type not defined. How can I do this?

Thanks for any help.
 
H

Herfried K. Wagner [MVP]

Dennis said:
I have a class named "myclass" and an arraylist
containing elements of type "MyClass".

Notice that 'MyClass' is a keyword in the VB.NET programming language.
I want to get the value of a property of "MyClass" (a string
type) for one of the arraylist elements.

I can get this using:
dim b as string
b = DirectCast(myarraylist(0),myclass).myproperty

However, I want to use an object to define the type "MyClass" like:
dim C as type = type.GetType(myarraylist(0))
b = DirectCast(myarraylist(0), C ).MyProperty

\\\
If TypeOf myarraylist(0) Is Foo Then
b = DirectCast(myarraylist(0), Foo).MyProperty
ElseIf...Then
...
....
End If
///
 
C

Cor Ligthert

Dennis,

I cannot offer you much, however this will work
\\\
Public Class Example
Public Shared Sub Main()
Dim myarraylist As New ArrayList
Dim mywhatever As New WindowsApplication1.myclass
myarraylist.Add(mywhatever)
Dim b As String = DirectCast(myarraylist(0), _
WindowsApplication1.myclass).myproperty
If TypeOf myarraylist(0) Is WindowsApplication1.myclass Then
MessageBox.Show(DirectCast(myarraylist(0), _
WindowsApplication1.myclass).myproperty)
End If
End Sub
End Class
Public Class [myclass]
Public myproperty As String
Public Sub New()
myproperty = "Hello World"
End Sub
End Class
///

I would not use that myclass because it is very confusing because it is a
keyword in VBNet.
(And I used an very easy way for a property only to keep it short)

I hope this helps anyway a little bit?

Cor
 
J

Jay B. Harlow [MVP - Outlook]

Dennis,
dim C as type = type.GetType(myarraylist(0))
b = DirectCast(myarraylist(0), C ).MyProperty

You cannot cast based on a Type variable, the DirectCast needs the name
(myclass) of the type at compile time.

If you truly want to get AnyProperty form an ArrayList of AnyClass, the
"easist" way is to use CallByName

Dim o As Object = CallByName(list(0), "MyProperty", CallType.Get)


Alternatively I will use a PropertyDescriptor or Reflection.

Something like:

Dim properties As System.ComponentModel.PropertyDescriptorCollection
properties =
System.ComponentModel.TypeDescriptor.GetProperties(list(0))

Dim o As Object = properties("MyProperty").GetValue(list(0))

However I normally only use PropertyDescriptor in more advanced cases...

Hope this helps
Jay
 
G

Guest

Thanks Jay and Cor. I was thinking about the CallbyName but I didn't know it
would work with a general arraylist of classes. Following is what I ended up
with that will sort any arraylist of classes (must be same class types) by
any string or integer or decimal property of the class in ascending or
descending order:

dim myArrayList as ArrayList
'Set each element of the ArrayList to any class (must all be of same type)
Dim mycomparer As New mycompare

mycomparer.propertyname = col
mycomparer.ascending = True
myArrayList.Sort(mycomparer)
.......
.......
__________________________________________________________________
Protected Class mycompare
Implements IComparer
Public propertyname As String
Public ascending As Boolean
Private Function Compare(ByVal x As Object, ByVal y As Object) As Integer
_ Implements IComparer.Compare
If ascending Then
Return New CaseInsensitiveComparer().Compare(CallByName(x, _
propertyname, CallType.Get), CallByName(y, propertyname, _ CallType.Get))
Else
Return New CaseInsensitiveComparer().Compare(CallByName(y, _
propertyname, CallType.Get), CallByName(x, propertyname, _ CallType.Get))
End If
End Function
End Class
_______________________________________________________________
 
J

Jay B. Harlow [MVP - Outlook]

Dennis,
Actually your code will work on two objects of different types as long as
they have the same property names.

For example, your class will compare the these two classes without any
problems:

Public Class Class1

Public ReadOnly Property Test() As String
...

End Class

Public Class Class2

Public ReadOnly Property Test() As String
...

End Class

Jay
 
G

Guest

You are, of course as usual, correct. I was just trying to simpify my
explaination. The major drawback, I think, is speed. I probably would be
faster to use the object with properties directly and use late binding rather
than CallbyName. But anyway, it's pretty fast for small arraylists, arrays,
etc. Thanks again for your help.
 
J

Jay B. Harlow [MVP - Outlook]

Dennis,
The major drawback, I think, is speed.
Which is where I would consider using a PropertyDescriptor instead of
CallByName in this case...

Something like:

Protected Class mycompare
Implements IComparer

Private ReadOnly m_property As
System.ComponentModel.PropertyDescriptor
Private ReadOnly m_ascending As Boolean

Public Sub New(ByVal componentType As Type, ByVal propertyName As
String, ByVal ascending As Boolean)
Dim properties As
System.ComponentModel.PropertyDescriptorCollection
properties =
System.ComponentModel.TypeDescriptor.GetProperties(componentType)
m_property = properties(propertyName)
m_ascending = ascending
End Sub

Private Function Compare(ByVal x As Object, ByVal y As Object) As
Integer Implements IComparer.Compare
x = m_property.GetValue(x)
y = m_property.GetValue(y)
If m_ascending Then
Return New CaseInsensitiveComparer().Compare(x, y)
Else
Return New CaseInsensitiveComparer().Compare(y, x)
End If
End Function

End Class

Hope this helps
Jay
 
C

Cor Ligthert

Dennis,

I hope you saw that my example was early binding.

It depends how many classes you use however in my idea can it be an easy
approach.

I can me not immaging a situation where you do not know what kind of objects
you add to your arraylist so it should be as well be possible to collect
them in that way of my sample back.

(And than of course in a If ElseIf piece of code)

I hope this helps?

Cor
 
G

Guest

I am working on an application for my personal use that uses several
arraylists each of which has differing classes (some of which I haven't even
designed yet) and I want to use a class that inherits a DataGrid which sorts
on the click of a button by different properties (columns) in different
arraylists.

I can then click on the datagrid's column header and sort the arrarylists no
matter which arraylist to which the DataGrid is bound. It works great with
the CallByName but I read where this can be slow in a loop, of which, sorting
is a loop(s).
 
G

Guest

Thanks a lot. I'll try the two different methods (callbyname and
Propertydescriptor) and see how much faster the PropertyDescriptor is. Just
curious as to why you made the m_Ascending a ReadOnly since it's private
anyway and can't be accessed outside the class.
 
J

Jay B. Harlow [MVP - Outlook]

Dennis,
I make member fields Read-only when the value of the field is not suppose to
change outside the Constructor (sub new) it keeps me honest when I am
writing the class, plus it keeps myself & subsequent programmers honest who
may modify the class later. Hopefully if they attempt to modify the field
and see it Read-only, then they will think a minute & research why its
read-only...

Hope this helps
Jay
 
G

Guest

I tried the PropertyDescriptor route and I found two things;

1) I had to add ".GeType.ToString" in use dim c as type =
type.GetType(myarraylist(0).GetType.ToString) to get it to compile

2) I get an error when it tries to sort in the
x=m_Property.GetValue(propertyName) that just says unhandled exception in
Icompare.

Any idea what is going on?
 
J

Jay B. Harlow [MVP - Outlook]

Dennis,
I suspect #2 is caused by #1.

I copied #1 from your original post. It should read:

Dim c As Type = myarraylist(0).GetType()

Or perferable:
Dim c As Type = GetType(AnyClass)

Where AnyClass is the class name of the objects you are putting into the
ArrayList.

Something like:

Public Class Class1

Public ReadOnly m_test As String

Public Sub New(ByVal test As String)
m_test = test
End Sub
Public ReadOnly Property Test() As String
Get
Return m_test
End Get
End Property

End Class

Public Shared Sub Main()
Dim myarraylist As New ArrayList
myarraylist.Add(New Class1("A"))
myarraylist.Add(New Class1("B"))
myarraylist.Add(New Class1("C"))

Const col As String = "Test"

Dim C As Type = GetType(Class1)

Dim mycomparer As New mycompare(C, col, True)
myarraylist.Sort(mycomparer)

Application.EnableVisualStyles()
Application.DoEvents()
Application.Run(New MainForm)
End Sub

Hope this helps
Jay
 
C

Cor Ligthert

Dennis,

And why can you than not use my solution?

Unlucky it can not in a select case because then it would be even more easy
to use.

Cor
 
J

Jay B. Harlow [MVP - Outlook]

Dennis,
I should add, that the PropertyDescriptor solution requires that all the
classes (in a single ArrayList) be the same type (it can be a common base
type).

Hope this helps
Jay
 
G

Guest

Jay, I got it working. You'll never believe what the real problem was. I
was passing the property name as I had specified it which was "Col1". The
propertyDescriptor converted it to lower case, i.e., "col1". When I passed
the lower case to the Icomparer routine, it works great. Thanks a lot for
you help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top