Class Modules

G

Greg

I’ve created the class below. It contains three properties (which I will be
referring to as fields). They are intProcessStep, strProcessCode and
strProcessDesc.

Public Class myProcess

Private m_strProcessCode As String
Private m_strProcessDesc As String
Private m_intProcessStep As Integer

Public Property strProcessCode() As String
Get
Return m_strProcessCode
End Get
Set(ByVal value As String)
m_strProcessCode = value
End Set
End Property

Public Property strProcessDesc() As String
Get
Return m_strProcessDesc
End Get
Set(ByVal value As String)
m_strProcessDesc = value
End Set
End Property

Public Property intProcessStep() As Integer
Get
Return m_intProcessStep
End Get
Set(ByVal value As Integer)
m_intProcessStep = value
End Set
End Property

End Class

Now, I can instantiate the class using the code below. This code snippet
allows me to store values in the class for a single record in this case.

Dim objProcess As New myProcess
objProcess.intProcessStep = 1
objProcess.strProcessCode = "New Code"
objProcess.strProcessDesc = "New Desc"

Now, this works fine for a single record. What I want to do though is define
objProcess as an array instead so that I can store more than a single record
in the class. I’d like to be able to assign values using something like
objProcess(0).intProcessStep, objProcess(1).intProcessStep,
objProcess(2).intProcessStep, etc, so that I may store one or more records in
the class. I tried the following. No error is initially reported, but when I
attempt to run the code, it stops.

Dim objProcess(2) As New myProcess
objProcess(0).intProcessStep = 1
objProcess(0).strProcessCode = "Code 1"
objProcess(0).strProcessDesc = "Desc 1"
objProcess(1).intProcessStep = 1
objProcess(1).strProcessCode = "Code 2"
objProcess(1).strProcessDesc = "Desc 2"

Is it possible to instantiate the myProcess class as an array or something
along this line as I’m suggesting?

Now, I’d like to pass this class to a function. The function will have no
prior knowledge of what the class contains, so it needs to be able to examine
the class to figure what properties (fields) it contains. And, when the field
is found, it needs to be able to read the data from that field. How could
this be done in the function when the class is passed?

Then, finally, assuming I can create the class as an array, how could I
determine the size of the array from the function it’s passed to so that I
can retrieve the data from each record.
 
S

Stephany Young

I cannot believe that the code is just stopping. You must be getting an
exception that tells you that an object is not assigned or the like.

You are attempting to create an array that can hold 3 instances of MyProcess
but you are never instantiating any MyProcess objects. You need to modify
the code to:

Dim objProcess(2) As myProcess
objProcess(0) = New myProcess
objProcess(0).intProcessStep = 1
objProcess(0).strProcessCode = "Code 1"
objProcess(0).strProcessDesc = "Desc 1"
objProcess(1) = New myProcess
objProcess(1).intProcessStep = 1
objProcess(1).strProcessCode = "Code 2"
objProcess(1).strProcessDesc = "Desc 2"

As for the next question, it is a simple matter of:

Function MyFunction(processes as myProcess()) As Whatever

...

End Function

As for the third question, have you thought of processes.Length?
 
J

Jack Jackson

I’ve created the class below. It contains three properties (which I will be
referring to as fields). They are intProcessStep, strProcessCode and
strProcessDesc.

Public Class myProcess

Private m_strProcessCode As String
Private m_strProcessDesc As String
Private m_intProcessStep As Integer

Public Property strProcessCode() As String
Get
Return m_strProcessCode
End Get
Set(ByVal value As String)
m_strProcessCode = value
End Set
End Property

Public Property strProcessDesc() As String
Get
Return m_strProcessDesc
End Get
Set(ByVal value As String)
m_strProcessDesc = value
End Set
End Property

Public Property intProcessStep() As Integer
Get
Return m_intProcessStep
End Get
Set(ByVal value As Integer)
m_intProcessStep = value
End Set
End Property

End Class

Now, I can instantiate the class using the code below. This code snippet
allows me to store values in the class for a single record in this case.

Dim objProcess As New myProcess
objProcess.intProcessStep = 1
objProcess.strProcessCode = "New Code"
objProcess.strProcessDesc = "New Desc"

Now, this works fine for a single record. What I want to do though is define
objProcess as an array instead so that I can store more than a single record
in the class. I’d like to be able to assign values using something like
objProcess(0).intProcessStep, objProcess(1).intProcessStep,
objProcess(2).intProcessStep, etc, so that I may store one or more records in
the class. I tried the following. No error is initially reported, but when I
attempt to run the code, it stops.

Dim objProcess(2) As New myProcess
objProcess(0).intProcessStep = 1
objProcess(0).strProcessCode = "Code 1"
objProcess(0).strProcessDesc = "Desc 1"
objProcess(1).intProcessStep = 1
objProcess(1).strProcessCode = "Code 2"
objProcess(1).strProcessDesc = "Desc 2"

Is it possible to instantiate the myProcess class as an array or something
along this line as I’m suggesting?

I would use an ArrayList. A generic list would generally be better
(List(Of T)), but since you want to pass different types of these to
one function I think you have to use ArrayList.

dim myList as New ArrayList
dim objProcess as myProcess

objProcess = New myProcess
objProcess.intProcessStep = 1
....
myList.Add(objProcess)
....

# items in list is myList.Count.
myList.Item(0) is the first item in the list.
Now, I’d like to pass this class to a function. The function will have no
prior knowledge of what the class contains, so it needs to be able to examine
the class to figure what properties (fields) it contains. And, when the field
is found, it needs to be able to read the data from that field. How could
this be done in the function when the class is passed?

Use Reflection. Look at the docs for PropertyDescriptor and
TypeDescriptor.GetProperties.
Then, finally, assuming I can create the class as an array, how could I
determine the size of the array from the function it’s passed to so that I
can retrieve the data from each record.

Fcn(myList)

Private Sub Fcn(lst as ArrayList)

For Each obj As Object in lst

Next
 
H

Herfried K. Wagner [MVP]

Greg said:
I’ve created the class below. It contains three properties (which I will
be
referring to as fields). They are intProcessStep, strProcessCode and
strProcessDesc.

Public Class myProcess

Private m_strProcessCode As String
Private m_strProcessDesc As String
Private m_intProcessStep As Integer

Public Property strProcessCode() As String
Get
Return m_strProcessCode
End Get
Set(ByVal value As String)
m_strProcessCode = value
End Set
End Property

Public Property strProcessDesc() As String
Get
Return m_strProcessDesc
End Get
Set(ByVal value As String)
m_strProcessDesc = value
End Set
End Property

Public Property intProcessStep() As Integer
Get
Return m_intProcessStep
End Get
Set(ByVal value As Integer)
m_intProcessStep = value
End Set
End Property

End Class

Now, I can instantiate the class using the code below. This code snippet
allows me to store values in the class for a single record in this case.

Dim objProcess As New myProcess
objProcess.intProcessStep = 1
objProcess.strProcessCode = "New Code"
objProcess.strProcessDesc = "New Desc"

Now, this works fine for a single record. What I want to do though is
define
objProcess as an array instead so that I can store more than a single
record
in the class. I’d like to be able to assign values using something like
objProcess(0).intProcessStep, objProcess(1).intProcessStep,
objProcess(2).intProcessStep, etc, so that I may store one or more records
in
the class. I tried the following. No error is initially reported, but when
I
attempt to run the code, it stops.

Dim objProcess(2) As New myProcess
objProcess(0).intProcessStep = 1
objProcess(0).strProcessCode = "Code 1"
objProcess(0).strProcessDesc = "Desc 1"
objProcess(1).intProcessStep = 1
objProcess(1).strProcessCode = "Code 2"
objProcess(1).strProcessDesc = "Desc 2"

Is it possible to instantiate the myProcess class as an array or something
along this line as I’m suggesting?

\\\
Dim Processes(20) As Process
For i As Integer = 0 To Processes.Length - 1
Processes(i) = New Process()
Next i
Process(0).ProcessStep = ...
....
///
Now, I’d like to pass this class to a function. The function will have no
prior knowledge of what the class contains, so it needs to be able to
examine
the class to figure what properties (fields) it contains. And, when the
field
is found, it needs to be able to read the data from that field. How could
this be done in the function when the class is passed?

Change the parameter's type.

For an array of objects:

\\\
Private Sub Foo(ByVal Processes() As Process)
...
End Sub
///

For a single 'Process' item:

\\\
Private Sub Foo(ByVal Process As Process)
...
End Sub
///
Then, finally, assuming I can create the class as an array, how could I
determine the size of the array from the function it’s passed to so that I
can retrieve the data from each record.

See above ('Length' property).
 
G

Guru

I would use an ArrayList.

Dichhead. ArrayList implements only the ICollection interface and the IList
derivative. You will make his code run as slow as all buggery.
 
G

Guru

Herfried K. Wagner said:
\\\
Dim Processes(20) As Process
For i As Integer = 0 To Processes.Length - 1
Processes(i) = New Process()
Next i
Process(0).ProcessStep = ...
...
///

BWAHAHAHAHAHAH! You forgot to tell him that he needs to know in advance how
many objects he will have if he used your stuffed up suggestion.
Change the parameter's type.

For an array of objects:

\\\
Private Sub Foo(ByVal Processes() As Process)
...
End Sub
///

BWAHAHAHAHAHAHAH! You just gave him code to pass strongly-typed "Process"
objects. He needs OBJECTS, you less than useless tapeworm.
For a single 'Process' item:

\\\
Private Sub Foo(ByVal Process As Process)
...
End Sub
///


See above ('Length' property).

BWAHAHAHAHAHA! Based on your stupid code, his array is always the same
..Length, no matter how many objects he actually has, you freaking foole.
 
G

Greg

You are right, I recall I was getting an error message stating something with
regards to the New Keyword. I was justing doing it wrong, rather than
instantiating each class object in the array, I was tried to instantiate the
whole array at once, using

objProcess = New myProcess

rather than what you are recommending, which works great and opens the door
to explore in more detail what I hope I can do with this.

objProcess(0) = New myProcess
objProcess(1) = New myProcess

This actually makes more sense now that I look at it.

Thanks for your help.

Greg
 
G

Guru

Greg said:
I've created the class below. It contains three properties (which I will
be
referring to as fields). They are intProcessStep, strProcessCode and
strProcessDesc.

Public Class myProcess

Private m_strProcessCode As String
Private m_strProcessDesc As String
Private m_intProcessStep As Integer

Public Property strProcessCode() As String
Get
Return m_strProcessCode
End Get
Set(ByVal value As String)
m_strProcessCode = value
End Set
End Property

Public Property strProcessDesc() As String
Get
Return m_strProcessDesc
End Get
Set(ByVal value As String)
m_strProcessDesc = value
End Set
End Property

Public Property intProcessStep() As Integer
Get
Return m_intProcessStep
End Get
Set(ByVal value As Integer)
m_intProcessStep = value
End Set
End Property

End Class

Now, I can instantiate the class using the code below. This code snippet
allows me to store values in the class for a single record in this case.

Dim objProcess As New myProcess
objProcess.intProcessStep = 1
objProcess.strProcessCode = "New Code"
objProcess.strProcessDesc = "New Desc"

Now, this works fine for a single record. What I want to do though is
define objProcess as an array instead so that I can store more than a
single record in the class. I'd like to be able to assign values using
something like
objProcess(0).intProcessStep, objProcess(1).intProcessStep,
objProcess(2).intProcessStep, etc, so that I may store one or more records
in the class. I tried the following. No error is initially reported, but
when I attempt to run the code, it stops.
Dim objProcess(2) As New myProcess
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Arrays cannot be declared with the New
statement. This code should not even compile, let alone stop during
execution. Besides, what is the meaning of "it stops"? Rhetorical question,
don't answer.
objProcess(0).intProcessStep = 1
objProcess(0).strProcessCode = "Code 1"
objProcess(0).strProcessDesc = "Desc 1"
objProcess(1).intProcessStep = 1
objProcess(1).strProcessCode = "Code 2"
objProcess(1).strProcessDesc = "Desc 2"

You must create the array then create the new object, like this, in
long-hand:

Dim objProcess(1) As myProcess ' Note 1, not 2 as you have it
Dim NewProcess As myProcess

NewProcess = New myProcess
NewProcess.intProcessStep = 1
NewProcess.strProcessCode = "Code 1"
NewProcess.strProcessDesc = "Desc 1"

objProcess(0) = NewProcess
NewProcess = New myProcess
NewProcess.intProcessStep = 1
NewProcess.strProcessCode = "Code 2"
NewProcess.strProcessDesc = "Desc 2"

objProcess(1) = NewProcess

Or like this, in short-hand:

Dim objProcess(1) As myProcess ' Note 1, not 2 as you have it

objProcess(0) = New myProcess
objProcess(0).intProcessStep = 1
objProcess(0).strProcessCode = "Code 1"
objProcess(0).strProcessDesc = "Desc 1"

objProcess(1) = New myProcess
objProcess(1).intProcessStep = 1
objProcess(1).strProcessCode = "Code 2"
objProcess(1).strProcessDesc = "Desc 2"
Is it possible to instantiate the myProcess class as an array or something
along this line as I'm suggesting?

If you need keyed access and/or index-based access then use a Dictionary(Of
TKey, TValue), and if you want sorted, keyed access, use a
SortedDictionary(Of TKey, TValue). If the keys must be unique then you can
also incorporate a HashTable.

There is also a SortedList(Of TKey, TValue), which should be avoided because
it is extremely slow when compared to Dictioanry options available to you. A
SortedDictionary is exponentially faster than any List type that implements
the simple Collection interface, so avoid the latter also, and if speed is a
consideration then ignore the advice you were given to implement an
ArrayList, which is also just a glorified simple Collection and will not
give you optimum speed.
Now, I'd like to pass this class to a function. The function will have no
prior knowledge of what the class contains, so it needs to be able to
examine the class to figure what properties (fields) it contains. And,
when the field is found, it needs to be able to read the data from that
field. How could this be done in the function when the class is passed?

Assuming you use a dictionary and a string key, you can weakly-type the
dictionary like this:

Dim DictOfMyProcess(Of String, Object)

[Do some stuff to fill DictOfMyProcess]
[DictOfMyProcess.Add("SomeKeyValue, MyProcess]

Call NoPriorKnowledge(DictOfMyProcess)

Private Sub NoPriorKnowledge(ByVal Dict As SortedDictionary(Of String, _
Object))
Then, finally, assuming I can create the class as an array, how could I
determine the size of the array from the function it's passed to so that I
can retrieve the data from each record.

Within Sub NoPriorKnowledge, use Dict.Count

There are problems with the code you posted, btw.
Dim objProcess(2) As myProcess

You only added two objects but the length of the array is 3. Array
dimensions are 0-based, not unary-based. Use this:

Dim objProcess(1) As myProcess

However using your method and the silly code suggested by that less than
useless MVP means you must know in advance how many elements you need, or
you must use ReDim Preserve and extend the array using the UBound() value of
the array plus one.

If you use a fixed array size then your NoPriorKnowledge method cannot ever
guarantee it can tell how many elements are populated as opposed to how many
elements there are in total; these are two completely different things in
the code you posted, which says there are 3 items but only 2 were added.

If you want to get out of the problem hastily, use a List(Of T) or an
ArrayList(), otherwise I recommend using dictionaries wherever possible for
the sake of speed and convenience. The nice thing about using a dictionary
is that you can make the key meaningful to your NoPriorKnowledge method by
putting something in there that tells the NoPriorKnowledge method exactly
what the contents of each and every dictionary is. In this way you can send
NoPriorKnowledge a dictionary of objects with a multitude of differnt types
attached, in the manner shown below (at end). The approach makes very good
sense because:

Even though it is true that method NoPriorKnowledge has no prior knowledge
of the object type, the creator of the object does have that knowledge, so
by putting soemthing in the key that represents what the creator knows, i.e.
the object type that it created, the NoPriorKnowledge method only has to
decide what to do with a certain type of object; it does not have to
determine what the type of object is because that has already been decided
out by the creator of the object.

If you go down the path of just passing object to the NoPriorKnowledge
method then the NoPriorKnowledge method must redo all the work done by the
method that put the object there in the first place, that is, the
NoPriorKnowledge method must determine what the object is. Double work for
zero benefit.

Private Sub DoSomething

Dim AnInteger As Integer = 99
Dim SomeOtherProcess As String = "Some text here"
Dim AProcess as New MyProcess

Dim DictOfStrangeObjects As New SortedDictionary(Of String, Object)

DictOfStrangeObjects.Add("INT", AnInteger)
DictOfStrangeObjects.Add("OtherProcess", SomeOtherProcess)
DictOfStrangeObjects.Add("MyProcess", AProcess)

Call NoPriorKowledge(DictOfStrangeObjects)

End Sub

Private Sub NoPriorKowledge(ByVal DictOfStrangeObjects As _
SortedDictionary(Of String, Object))

For Each StrangeObject As KeyValuePair(Of String, Object) In _
DictOfStrangeObjects
Select Case StrangeObject.Key
Case "INT"
DoSomethingWeird(StrangeObject.Value)
Case "OtherProcess"
DoSomethingEvenWeirder(StrangeObject.Value)
Case "MyProcess"
DoSomethingWithMyProcess(StrangeObject.Value)
End Select
Next

End Sub

Private Sub DoSomethingWithMyProcess(ByVal AProcess As MyProcess)

[...]

End Sub

Private Sub DoSomethingWeird(ByVal SomeStrangeObject As Object)

[...]

End Sub

Private Sub DoSomethingEvenWeirder(ByVal SomeStrangeObject As Object)

[...]

End Sub


In the code above, method DoSomethingWeird gets an integer, method
DoSomethingEvenWeirder gets a string, and DoSomethingWithMyProcess gets
a MyProcess object, and at no time did the NoPriorKowledge method ever
concern itself with the type of data it was given, in other words, the
NoPriorKowledge method is fully type agnostic, it doesn't care, and it
doesn't need to care; it only needs to know what to do when given a
certain piece of information.
 
L

Linda Liu[MSFT]

Hi Greg,

As for your first question, the answer from Stephany is correct.

As for your second question, you can make use of the
TypeDescriptor.GetProperties method the retrieve all the properties of an
object or a type. Then you can call the PropertyDescriptor.GetValue method
to get the value of the property.

As for your third question, you can define the type of the array as Array
and use the Array.Length property to get the number of the items in the
passed array.

The following a sample to answer all your three questions.

Imports System.ComponentModel

Public Class Form1

Public Class myProcess

Private m_strProcessCode As String
Private m_strProcessDesc As String
Private m_intProcessStep As Integer

Public Property strProcessCode() As String
Get
Return m_strProcessCode
End Get
Set(ByVal value As String)
m_strProcessCode = value
End Set
End Property

Public Property strProcessDesc() As String
Get
Return m_strProcessDesc
End Get
Set(ByVal value As String)
m_strProcessDesc = value
End Set
End Property

Public Property intProcessStep() As Integer
Get
Return m_intProcessStep
End Get
Set(ByVal value As Integer)
m_intProcessStep = value
End Set
End Property

End Class

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim objProcess(2) As myProcess
objProcess(0) = New myProcess
objProcess(0).intProcessStep = 1
objProcess(0).strProcessCode = "Code 1"
objProcess(0).strProcessDesc = "Desc 1"
objProcess(1) = New myProcess
objProcess(1).intProcessStep = 2
objProcess(1).strProcessCode = "Code 2"
objProcess(1).strProcessDesc = "Desc 2"
objProcess(2) = New myProcess
objProcess(2).intProcessStep = 3
objProcess(2).strProcessCode = "Code 3"
objProcess(2).strProcessDesc = "Desc 3"

PrintArray(objProcess)
End Sub

Sub PrintArray(ByRef arrays As Array)
For i As Integer = 0 To arrays.Length - 1
Console.WriteLine("item " & i.ToString() & ":")
PrintObject(arrays(i))
Next
End Sub

Sub PrintObject(ByRef obj As Object)
Dim pdc As PropertyDescriptorCollection =
TypeDescriptor.GetProperties(obj)
For Each pd As PropertyDescriptor In pdc
Console.WriteLine(pd.Name & " = " & pd.GetValue(obj).ToString())
Next
End Sub
End Class

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
C

Cor Ligthert [MVP]

Linda,
As for your first question, the answer from Stephany is correct.

I strongly disagree with you.

I don't think that a MSFT should interfear in answers in the community with
telling what is correct and with that implecitely tell what are wrong
answers.

Although Stephany's answer is correct is in my opinion the way to go to this
generics.
But in my opinion there are no wrong answer in this message thread.

Cor
 
B

Bill McCarthy

Hi Linda,

Good code. I would make a couple of changes though. In particular the
arguments for PrintArray and PrintObject do not need to be ByRef, so I would
make them ByVal. I'd also suggest using IList instead of Array, as this
will allow him to use different storage mechanisms without changing that
code, e:g

Sub PrintArray(ByVal items As IList)
For i As Integer = 0 To items.Count - 1
Console.WriteLine("item " & i.ToString() & ":")
PrintObject(items(i))
Next
End Sub

Sub PrintObject(ByVal obj As Object)
Dim pdc As PropertyDescriptorCollection =
TypeDescriptor.GetProperties(obj)
For Each pd As PropertyDescriptor In pdc
Console.WriteLine(pd.Name & " = " & pd.GetValue(obj).ToString())
Next
End Sub
 

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