converting the use of interfaces under vb6 to vb.net

G

Guest

I am converting (attempting) some vb6 code that makes vast use of interfaces.
One of the major uses is to be able to split out Read-only access to an
obect. Let me give you a simple (contrived) example:
In Project RoObjDefs:
RoPerson.cls file:
Public Property Get FirstName() as String
Public Property Get LastName() as String
<end of file RoPerson.cls>
RoPersons.cls file
Public Function Count() as Integer
Public Function Item(Index as Variant) as Person
Public Function NewEnum() as IUnknown
<end of file RoPersons.cls>

Then in Project RwObjDefs:
Person.cls file
Implements RoObjDefs.RoPerson
Private mFirstName as String
Private mFirstName as String
....
Public Property Get FirstName() as String
FirstName = mFirstName
End Property
Public Property Set FirstName(byval val as string)
mFirstName = val
End Properety
....
Private Property Get RoPerson_FirstName() as String
RoPerson_FirstName = mFirstName
End Property
....
<end of Person.cls file>

In file Persons.cls
mPersons as collection
....(Code for add, item, remove, clear...)
Public Function NewEnum() As IUnknown
Set NewEnum = mPersons.[_NewEnum]
End Function
....(implement the RO functions, like in Person class above)
<end of Persons.cls>

I could then 'cast' a Person to an RoPerson, when I only wanted to give out
a readonly interface.
I find when I attempt this that I can not do it though the use of
interfaces. At least I cant if I want the properties to have the same name
on both of the interfaces.
My guess is that I should now do this with inheritance. For example:

Public Class RoPerson
Protected mFirstName as string
Public Readonly Property FirstName() as string
Return mFirstName
End Property
....
and then in another class:
Public Class Person
Inherits RoPerson
Public Shadows Property FirstName() As String
Get
Return MyBase.FirstName
End Get
Set(byval value as string)
MyBase.mFirstName = value
End Set
....

Then like under VB6, I could 'cast' the object to its base when returning a
reference to a readonly user.
So, is this the best (only) way to accomplish what I was doing using
interfaces in VB6? And, how do I implement 'enumeration' for my custom
collections in .Net? That is with out giving them remove, clear and any
other 'write' type functions that are implemented in the base class.

Thanks in advance for your guidance.
 
C

Cor Ligthert [MVP]

Terry,

AFAIK is the interface in VBNet is a contract which tells that a certain
member exist in a class despite the name it is used, The last can be told in
the class by mentioning that.

The member has however forever the same contract, it is not his name but its
behaviour that counts.

I hope this helps,

Cor
 
L

Linda Liu [MSFT]

Hi Terry,

Thank you for posting.

Would you tell me what you mean by "I find when I attempt this that I can
not do it though the use of interfaces. At least I can't if I want the
properties to have the same name on both of the interfaces."?

In .NET, you should use Interface to declare a set of properties and
methods. There's still a Collection class in VB.NET which you could use to
implement "enumeration" in the class implementing the Interface RoPersons.

I am looking forward to your response.


Sincerely,
Linda Liu
Microsoft Online Community Support

====================================================
When responding to posts,please "Reply to Group" via
your newsreader so that others may learn and benefit
from your issue.
====================================================
 
J

Jay B. Harlow [MVP - Outlook]

Terry,
In addition to the other comments:

| So, is this the best (only) way to accomplish what I was doing using
| interfaces in VB6?

Rather then use Shadows & inheritance.

I would recommend to use "explicit interface implementation" something like:

Public Interface IReadonlyPerson

ReadOnly Property FirstName() As String
ReadOnly Property LastName() As String

End Interface

Public Class Person
Implements IReadonlyPerson

Public Property FirstName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Property LastName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

#Region " IReadonlyPerson support "

Private ReadOnly Property IReadonlyPerson_FirstName() As String
Implements IReadonlyPerson.FirstName
Get
Return FirstName
End Get
End Property

Private ReadOnly Property IReadonlyPerson_LastName() As String
Implements IReadonlyPerson.LastName
Get
Return LastName
End Get
End Property

#End Region

End Class

Unfortunately any code that receives an IReadonlyPerson value can simply
cast it back to Person to gain full access to the object. If you want a true
Readonly Person I would create a Readonly Person class that delegated
(wrapped) a Person object. Something like:

Public Class ReadonlyPerson

Private ReadOnly m_person As Person

Public Sub New(ByVal person As Person)
m_person = person
End Sub

Public ReadOnly Property FirstName() As String
Get
Return m_person.FirstName
End Get
End Property
Public ReadOnly Property LastName() As String
Get
Return m_person.LastName
End Get
End Property

End Class

Public Class Person

Public Property FirstName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Property LastName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Function AsReadonly() As ReadonlyPerson
Return New ReadonlyPerson(Me)
End Function

End Class

Of course using Reflection one could break the contract with ReadonlyPerson,
however that would be more effort...

| And, how do I implement 'enumeration' for my custom
| collections in .Net? That is with out giving them remove, clear and any
| other 'write' type functions that are implemented in the base class.
In .NET 1.x I would recommend inheriting from
System.Collections.CollectionBase:

Public Class PersonCollection
Inherits System.Collections.CollectionBase

Default Public Property Item(ByVal index As Integer) As Person
Get
Return DirectCast(List.Item(index), Person)
End Get
Set(ByVal value As Person)
List.Item(index) = value
End Set
End Property

Public Sub Add(ByVal value As Person)
List.Add(value)
End Sub

Public Function Contains(ByVal value As Person) As Boolean
Return List.Contains(value)
End Function

Public Function IndexOf(ByVal value As Person) As Integer
Return List.IndexOf(value)
End Function

Public Sub Insert(ByVal index As Integer, ByVal value As Person)
List.Insert(index, value)
End Sub

Public Sub Remove(ByVal value As Person)
List.Remove(value)
End Sub

Protected Overrides Sub OnValidate(ByVal value As Object)
If TypeOf value Is Person Then Return
Throw New InvalidCastException
End Sub

End Class

The OnValidate ensures that only Person objects are added to the collection
when using the IList interface exposed by the collection...
CollectionBase.List (as above) uses the IList interface, while
CollectionBase.InnerList uses the contained (wrapped) ArrayList object.
Primarily InnerList.Add will not cause the OnValidate event to be raised...

In .NET 2.0 I would recommend inheriting from Collection(Of T).

Public Class PersonCollection
Inherits System.Collections.ObjectModel.Collection(Of Person)

End Class

YES! that is all the code you need with .NET 2.0!


--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


|I am converting (attempting) some vb6 code that makes vast use of
interfaces.
| One of the major uses is to be able to split out Read-only access to an
| obect. Let me give you a simple (contrived) example:
| In Project RoObjDefs:
| RoPerson.cls file:
| Public Property Get FirstName() as String
| Public Property Get LastName() as String
| <end of file RoPerson.cls>
| RoPersons.cls file
| Public Function Count() as Integer
| Public Function Item(Index as Variant) as Person
| Public Function NewEnum() as IUnknown
| <end of file RoPersons.cls>
|
| Then in Project RwObjDefs:
| Person.cls file
| Implements RoObjDefs.RoPerson
| Private mFirstName as String
| Private mFirstName as String
| ...
| Public Property Get FirstName() as String
| FirstName = mFirstName
| End Property
| Public Property Set FirstName(byval val as string)
| mFirstName = val
| End Properety
| ...
| Private Property Get RoPerson_FirstName() as String
| RoPerson_FirstName = mFirstName
| End Property
| ...
| <end of Person.cls file>
|
| In file Persons.cls
| mPersons as collection
| ...(Code for add, item, remove, clear...)
| Public Function NewEnum() As IUnknown
| Set NewEnum = mPersons.[_NewEnum]
| End Function
| ...(implement the RO functions, like in Person class above)
| <end of Persons.cls>
|
| I could then 'cast' a Person to an RoPerson, when I only wanted to give
out
| a readonly interface.
| I find when I attempt this that I can not do it though the use of
| interfaces. At least I cant if I want the properties to have the same
name
| on both of the interfaces.
| My guess is that I should now do this with inheritance. For example:
|
| Public Class RoPerson
| Protected mFirstName as string
| Public Readonly Property FirstName() as string
| Return mFirstName
| End Property
| ...
| and then in another class:
| Public Class Person
| Inherits RoPerson
| Public Shadows Property FirstName() As String
| Get
| Return MyBase.FirstName
| End Get
| Set(byval value as string)
| MyBase.mFirstName = value
| End Set
| ...
|
| Then like under VB6, I could 'cast' the object to its base when returning
a
| reference to a readonly user.
| So, is this the best (only) way to accomplish what I was doing using
| interfaces in VB6? And, how do I implement 'enumeration' for my custom
| collections in .Net? That is with out giving them remove, clear and any
| other 'write' type functions that are implemented in the base class.
|
| Thanks in advance for your guidance.
| --
| Terry
 
G

Guest

Hi Jay,
Thanks for the help!

First, I had just spent several hours on a responce to you (along with other
things)and when I 'posted' it, I was taken back to the logon page and my
entire response was lost! Is that normal? Is there a timeout on this site
or was it just a glitch?

Ok, so I can use interfaces in the same way as I did in VB6. Guess I got
off on the wrong foot when the IDE inserted public readonly properties using
the same name as soon as I typed in the Implements clasue. Thought I had to
leave the property names alone (as in VB6).
As far as the custom collections go, I really would prefer NOT to expose
'Add', 'Remove', etc to the client objects. This is a commercial product
and the API it exposes needs to be 'clean', and not contain methods and
properties that they should not use.
If I inherit from one of the base collection classes, then I will expose all
these methods. So, I wish to wrap one of the collection classes as I did in
VB6. Is the .Net equivalent of the VB6 collection object a
System.Collections.Hashtable? And if I wanted to use a generic collection
would I use a 'Dictionary' as the closest thing to the VB6 collection type?

In VB6 you provided 'enumeration' for your custom collections by including
the following code in your class:
Public Function NewEnum() As IUnknown
Set NewEnum = mPersons.[_NewEnum]
End Function
and setting the ProcedureId to -4 (Under Procedure Attributes/Advanced)
Is the .Net equivelant (for the generic case):
Public Function GetEnumerator() as
System.Collections.Generic.Dictionary.Enumerator
return mPersons.GetEnumerator()
end function

Thanks again for all your help!!!
--
Terry


Jay B. Harlow said:
Terry,
In addition to the other comments:

| So, is this the best (only) way to accomplish what I was doing using
| interfaces in VB6?

Rather then use Shadows & inheritance.

I would recommend to use "explicit interface implementation" something like:

Public Interface IReadonlyPerson

ReadOnly Property FirstName() As String
ReadOnly Property LastName() As String

End Interface

Public Class Person
Implements IReadonlyPerson

Public Property FirstName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Property LastName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

#Region " IReadonlyPerson support "

Private ReadOnly Property IReadonlyPerson_FirstName() As String
Implements IReadonlyPerson.FirstName
Get
Return FirstName
End Get
End Property

Private ReadOnly Property IReadonlyPerson_LastName() As String
Implements IReadonlyPerson.LastName
Get
Return LastName
End Get
End Property

#End Region

End Class

Unfortunately any code that receives an IReadonlyPerson value can simply
cast it back to Person to gain full access to the object. If you want a true
Readonly Person I would create a Readonly Person class that delegated
(wrapped) a Person object. Something like:

Public Class ReadonlyPerson

Private ReadOnly m_person As Person

Public Sub New(ByVal person As Person)
m_person = person
End Sub

Public ReadOnly Property FirstName() As String
Get
Return m_person.FirstName
End Get
End Property
Public ReadOnly Property LastName() As String
Get
Return m_person.LastName
End Get
End Property

End Class

Public Class Person

Public Property FirstName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Property LastName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Function AsReadonly() As ReadonlyPerson
Return New ReadonlyPerson(Me)
End Function

End Class

Of course using Reflection one could break the contract with ReadonlyPerson,
however that would be more effort...

| And, how do I implement 'enumeration' for my custom
| collections in .Net? That is with out giving them remove, clear and any
| other 'write' type functions that are implemented in the base class.
In .NET 1.x I would recommend inheriting from
System.Collections.CollectionBase:

Public Class PersonCollection
Inherits System.Collections.CollectionBase

Default Public Property Item(ByVal index As Integer) As Person
Get
Return DirectCast(List.Item(index), Person)
End Get
Set(ByVal value As Person)
List.Item(index) = value
End Set
End Property

Public Sub Add(ByVal value As Person)
List.Add(value)
End Sub

Public Function Contains(ByVal value As Person) As Boolean
Return List.Contains(value)
End Function

Public Function IndexOf(ByVal value As Person) As Integer
Return List.IndexOf(value)
End Function

Public Sub Insert(ByVal index As Integer, ByVal value As Person)
List.Insert(index, value)
End Sub

Public Sub Remove(ByVal value As Person)
List.Remove(value)
End Sub

Protected Overrides Sub OnValidate(ByVal value As Object)
If TypeOf value Is Person Then Return
Throw New InvalidCastException
End Sub

End Class

The OnValidate ensures that only Person objects are added to the collection
when using the IList interface exposed by the collection...
CollectionBase.List (as above) uses the IList interface, while
CollectionBase.InnerList uses the contained (wrapped) ArrayList object.
Primarily InnerList.Add will not cause the OnValidate event to be raised...

In .NET 2.0 I would recommend inheriting from Collection(Of T).

Public Class PersonCollection
Inherits System.Collections.ObjectModel.Collection(Of Person)

End Class

YES! that is all the code you need with .NET 2.0!


--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


|I am converting (attempting) some vb6 code that makes vast use of
interfaces.
| One of the major uses is to be able to split out Read-only access to an
| obect. Let me give you a simple (contrived) example:
| In Project RoObjDefs:
| RoPerson.cls file:
| Public Property Get FirstName() as String
| Public Property Get LastName() as String
| <end of file RoPerson.cls>
| RoPersons.cls file
| Public Function Count() as Integer
| Public Function Item(Index as Variant) as Person
| Public Function NewEnum() as IUnknown
| <end of file RoPersons.cls>
|
| Then in Project RwObjDefs:
| Person.cls file
| Implements RoObjDefs.RoPerson
| Private mFirstName as String
| Private mFirstName as String
| ...
| Public Property Get FirstName() as String
| FirstName = mFirstName
| End Property
| Public Property Set FirstName(byval val as string)
| mFirstName = val
| End Properety
| ...
| Private Property Get RoPerson_FirstName() as String
| RoPerson_FirstName = mFirstName
| End Property
| ...
| <end of Person.cls file>
|
| In file Persons.cls
| mPersons as collection
| ...(Code for add, item, remove, clear...)
| Public Function NewEnum() As IUnknown
| Set NewEnum = mPersons.[_NewEnum]
| End Function
| ...(implement the RO functions, like in Person class above)
| <end of Persons.cls>
|
| I could then 'cast' a Person to an RoPerson, when I only wanted to give
out
| a readonly interface.
| I find when I attempt this that I can not do it though the use of
| interfaces. At least I cant if I want the properties to have the same
name
| on both of the interfaces.
| My guess is that I should now do this with inheritance. For example:
|
| Public Class RoPerson
| Protected mFirstName as string
| Public Readonly Property FirstName() as string
| Return mFirstName
| End Property
| ...
| and then in another class:
| Public Class Person
| Inherits RoPerson
| Public Shadows Property FirstName() As String
| Get
| Return MyBase.FirstName
| End Get
| Set(byval value as string)
| MyBase.mFirstName = value
| End Set
| ...
|
| Then like under VB6, I could 'cast' the object to its base when returning
a
| reference to a readonly user.
| So, is this the best (only) way to accomplish what I was doing using
| interfaces in VB6? And, how do I implement 'enumeration' for my custom
| collections in .Net? That is with out giving them remove, clear and any
| other 'write' type functions that are implemented in the base class.
|
| Thanks in advance for your guidance.
| --
| Terry
 
G

Guest

Hi Linda,
I think I answered your question in the response I just set to Jay.

"Ok, so I can use interfaces in the same way as I did in VB6. Guess I got
off on the wrong foot when the IDE inserted public readonly properties using
the same name as soon as I typed in the Implements clasue. Thought I had to
leave the property names alone (as in VB6)."

Thanks,

Terry
 
G

Guest

Hi Jay,
Please ignore my last post - I have figured this out (or at least I have
now made some progress). One thing I have learned for sure... stop using the
'search', and start using 'index' when looking for help. Been pulling out my
hair for 2 weeks thinks that the help engine was worthless! So there is
still a VB6 type collection and the only real change from VB6 custome
collections to VB.Net is that I now have to implement Ienumerable.
I also figured out how to do this with generics, the only real 'trick'
(to me anyways) was that instead of mPersons.Getenumerator, it was
Persons.Values.GetEnumerator.
I also came accross a 'ReadOnlyCollectionBase' that "Provides the
abstract base class for a strongly typed non-generic read-only collection."
This statement confuses me - thought that, by definition, non-generic
collections are considered to NOT be strongly typed. Cna you clarify this
for me?

Thanks again in advance.

--
Terry


Jay B. Harlow said:
Terry,
In addition to the other comments:

| So, is this the best (only) way to accomplish what I was doing using
| interfaces in VB6?

Rather then use Shadows & inheritance.

I would recommend to use "explicit interface implementation" something like:

Public Interface IReadonlyPerson

ReadOnly Property FirstName() As String
ReadOnly Property LastName() As String

End Interface

Public Class Person
Implements IReadonlyPerson

Public Property FirstName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Property LastName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

#Region " IReadonlyPerson support "

Private ReadOnly Property IReadonlyPerson_FirstName() As String
Implements IReadonlyPerson.FirstName
Get
Return FirstName
End Get
End Property

Private ReadOnly Property IReadonlyPerson_LastName() As String
Implements IReadonlyPerson.LastName
Get
Return LastName
End Get
End Property

#End Region

End Class

Unfortunately any code that receives an IReadonlyPerson value can simply
cast it back to Person to gain full access to the object. If you want a true
Readonly Person I would create a Readonly Person class that delegated
(wrapped) a Person object. Something like:

Public Class ReadonlyPerson

Private ReadOnly m_person As Person

Public Sub New(ByVal person As Person)
m_person = person
End Sub

Public ReadOnly Property FirstName() As String
Get
Return m_person.FirstName
End Get
End Property
Public ReadOnly Property LastName() As String
Get
Return m_person.LastName
End Get
End Property

End Class

Public Class Person

Public Property FirstName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Property LastName() As String
Get

End Get
Set(ByVal value As String)

End Set
End Property

Public Function AsReadonly() As ReadonlyPerson
Return New ReadonlyPerson(Me)
End Function

End Class

Of course using Reflection one could break the contract with ReadonlyPerson,
however that would be more effort...

| And, how do I implement 'enumeration' for my custom
| collections in .Net? That is with out giving them remove, clear and any
| other 'write' type functions that are implemented in the base class.
In .NET 1.x I would recommend inheriting from
System.Collections.CollectionBase:

Public Class PersonCollection
Inherits System.Collections.CollectionBase

Default Public Property Item(ByVal index As Integer) As Person
Get
Return DirectCast(List.Item(index), Person)
End Get
Set(ByVal value As Person)
List.Item(index) = value
End Set
End Property

Public Sub Add(ByVal value As Person)
List.Add(value)
End Sub

Public Function Contains(ByVal value As Person) As Boolean
Return List.Contains(value)
End Function

Public Function IndexOf(ByVal value As Person) As Integer
Return List.IndexOf(value)
End Function

Public Sub Insert(ByVal index As Integer, ByVal value As Person)
List.Insert(index, value)
End Sub

Public Sub Remove(ByVal value As Person)
List.Remove(value)
End Sub

Protected Overrides Sub OnValidate(ByVal value As Object)
If TypeOf value Is Person Then Return
Throw New InvalidCastException
End Sub

End Class

The OnValidate ensures that only Person objects are added to the collection
when using the IList interface exposed by the collection...
CollectionBase.List (as above) uses the IList interface, while
CollectionBase.InnerList uses the contained (wrapped) ArrayList object.
Primarily InnerList.Add will not cause the OnValidate event to be raised...

In .NET 2.0 I would recommend inheriting from Collection(Of T).

Public Class PersonCollection
Inherits System.Collections.ObjectModel.Collection(Of Person)

End Class

YES! that is all the code you need with .NET 2.0!


--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


|I am converting (attempting) some vb6 code that makes vast use of
interfaces.
| One of the major uses is to be able to split out Read-only access to an
| obect. Let me give you a simple (contrived) example:
| In Project RoObjDefs:
| RoPerson.cls file:
| Public Property Get FirstName() as String
| Public Property Get LastName() as String
| <end of file RoPerson.cls>
| RoPersons.cls file
| Public Function Count() as Integer
| Public Function Item(Index as Variant) as Person
| Public Function NewEnum() as IUnknown
| <end of file RoPersons.cls>
|
| Then in Project RwObjDefs:
| Person.cls file
| Implements RoObjDefs.RoPerson
| Private mFirstName as String
| Private mFirstName as String
| ...
| Public Property Get FirstName() as String
| FirstName = mFirstName
| End Property
| Public Property Set FirstName(byval val as string)
| mFirstName = val
| End Properety
| ...
| Private Property Get RoPerson_FirstName() as String
| RoPerson_FirstName = mFirstName
| End Property
| ...
| <end of Person.cls file>
|
| In file Persons.cls
| mPersons as collection
| ...(Code for add, item, remove, clear...)
| Public Function NewEnum() As IUnknown
| Set NewEnum = mPersons.[_NewEnum]
| End Function
| ...(implement the RO functions, like in Person class above)
| <end of Persons.cls>
|
| I could then 'cast' a Person to an RoPerson, when I only wanted to give
out
| a readonly interface.
| I find when I attempt this that I can not do it though the use of
| interfaces. At least I cant if I want the properties to have the same
name
| on both of the interfaces.
| My guess is that I should now do this with inheritance. For example:
|
| Public Class RoPerson
| Protected mFirstName as string
| Public Readonly Property FirstName() as string
| Return mFirstName
| End Property
| ...
| and then in another class:
| Public Class Person
| Inherits RoPerson
| Public Shadows Property FirstName() As String
| Get
| Return MyBase.FirstName
| End Get
| Set(byval value as string)
| MyBase.mFirstName = value
| End Set
| ...
|
| Then like under VB6, I could 'cast' the object to its base when returning
a
| reference to a readonly user.
| So, is this the best (only) way to accomplish what I was doing using
| interfaces in VB6? And, how do I implement 'enumeration' for my custom
| collections in .Net? That is with out giving them remove, clear and any
| other 'write' type functions that are implemented in the base class.
|
| Thanks in advance for your guidance.
| --
| Terry
 
J

Jay B. Harlow [MVP - Outlook]

Terry,
| Is the .Net equivalent of the VB6 collection object a
| System.Collections.Hashtable?
Microsoft.VisualBasic.Collection is .NET's equivalent to VB6's collection.
However I would not recommend using it as it normally does more then you
really want, plus it is 1 based as opposed to 0 based. 0 based collections
are prevalent in the Framework.

ArrayList & HashTable are .NET 1.x "common" collection's while List(Of T) &
Dictionary(Of T) are .NET 2.0 "common" collection.

By "common" I mean most versatile, where you would have used Collection in
VB6.

ArrayList & List(Of T) are used when you have an ordered collection of items
that do not have a key.

HashTable & Dictionary(Of T) are used when you have an unordered collection
of items that have a key.

CollectionBase, ReadOnlyCollectionBase and DictionaryBase are the .NET 1.x
way of doing things.
Collection(Of T), ReadonlyCollection(Of T), and KeyedCollection(Of T) are
the .NET 2.0 way of doing things.

NOTE: KeyedCollection(Of T) can be used for an ordered collection w/keys;
while DictionaryBase cannot.

| Is the .Net equivelant (for the generic case):
| Public Function GetEnumerator() as
| System.Collections.Generic.Dictionary.Enumerator
| return mPersons.GetEnumerator()
| end function
Yes call GetEnumerator is the equivelant, as I believe you found out. Be
careful some collections such as Dictionary(OF T) & HashTable are actually
collections of key/value pairs. Which means that the enumerator returns a
structure that contains both the key & the value. KeyedCollection(Of T)
returns an enumerator of just the value, as it is an IList(Of T) first, that
maintains a second collection of the keys...

--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Hi Jay,
| Thanks for the help!
|
| First, I had just spent several hours on a responce to you (along with
other
| things)and when I 'posted' it, I was taken back to the logon page and my
| entire response was lost! Is that normal? Is there a timeout on this
site
| or was it just a glitch?
|
| Ok, so I can use interfaces in the same way as I did in VB6. Guess I got
| off on the wrong foot when the IDE inserted public readonly properties
using
| the same name as soon as I typed in the Implements clasue. Thought I had
to
| leave the property names alone (as in VB6).
| As far as the custom collections go, I really would prefer NOT to expose
| 'Add', 'Remove', etc to the client objects. This is a commercial product
| and the API it exposes needs to be 'clean', and not contain methods and
| properties that they should not use.
| If I inherit from one of the base collection classes, then I will expose
all
| these methods. So, I wish to wrap one of the collection classes as I did
in
| VB6. Is the .Net equivalent of the VB6 collection object a
| System.Collections.Hashtable? And if I wanted to use a generic collection
| would I use a 'Dictionary' as the closest thing to the VB6 collection
type?
|
| In VB6 you provided 'enumeration' for your custom collections by including
| the following code in your class:
| Public Function NewEnum() As IUnknown
| Set NewEnum = mPersons.[_NewEnum]
| End Function
| and setting the ProcedureId to -4 (Under Procedure Attributes/Advanced)
| Is the .Net equivelant (for the generic case):
| Public Function GetEnumerator() as
| System.Collections.Generic.Dictionary.Enumerator
| return mPersons.GetEnumerator()
| end function
|
| Thanks again for all your help!!!
| --
| Terry
|
|
| "Jay B. Harlow [MVP - Outlook]" wrote:
|
| > Terry,
| > In addition to the other comments:
| >
| > | So, is this the best (only) way to accomplish what I was doing using
| > | interfaces in VB6?
| >
| > Rather then use Shadows & inheritance.
| >
| > I would recommend to use "explicit interface implementation" something
like:
| >
| > Public Interface IReadonlyPerson
| >
| > ReadOnly Property FirstName() As String
| > ReadOnly Property LastName() As String
| >
| > End Interface
| >
| > Public Class Person
| > Implements IReadonlyPerson
| >
| > Public Property FirstName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > Public Property LastName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > #Region " IReadonlyPerson support "
| >
| > Private ReadOnly Property IReadonlyPerson_FirstName() As String
| > Implements IReadonlyPerson.FirstName
| > Get
| > Return FirstName
| > End Get
| > End Property
| >
| > Private ReadOnly Property IReadonlyPerson_LastName() As String
| > Implements IReadonlyPerson.LastName
| > Get
| > Return LastName
| > End Get
| > End Property
| >
| > #End Region
| >
| > End Class
| >
| > Unfortunately any code that receives an IReadonlyPerson value can simply
| > cast it back to Person to gain full access to the object. If you want a
true
| > Readonly Person I would create a Readonly Person class that delegated
| > (wrapped) a Person object. Something like:
| >
| > Public Class ReadonlyPerson
| >
| > Private ReadOnly m_person As Person
| >
| > Public Sub New(ByVal person As Person)
| > m_person = person
| > End Sub
| >
| > Public ReadOnly Property FirstName() As String
| > Get
| > Return m_person.FirstName
| > End Get
| > End Property
| > Public ReadOnly Property LastName() As String
| > Get
| > Return m_person.LastName
| > End Get
| > End Property
| >
| > End Class
| >
| > Public Class Person
| >
| > Public Property FirstName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > Public Property LastName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > Public Function AsReadonly() As ReadonlyPerson
| > Return New ReadonlyPerson(Me)
| > End Function
| >
| > End Class
| >
| > Of course using Reflection one could break the contract with
ReadonlyPerson,
| > however that would be more effort...
| >
| > | And, how do I implement 'enumeration' for my custom
| > | collections in .Net? That is with out giving them remove, clear and
any
| > | other 'write' type functions that are implemented in the base class.
| > In .NET 1.x I would recommend inheriting from
| > System.Collections.CollectionBase:
| >
| > Public Class PersonCollection
| > Inherits System.Collections.CollectionBase
| >
| > Default Public Property Item(ByVal index As Integer) As Person
| > Get
| > Return DirectCast(List.Item(index), Person)
| > End Get
| > Set(ByVal value As Person)
| > List.Item(index) = value
| > End Set
| > End Property
| >
| > Public Sub Add(ByVal value As Person)
| > List.Add(value)
| > End Sub
| >
| > Public Function Contains(ByVal value As Person) As Boolean
| > Return List.Contains(value)
| > End Function
| >
| > Public Function IndexOf(ByVal value As Person) As Integer
| > Return List.IndexOf(value)
| > End Function
| >
| > Public Sub Insert(ByVal index As Integer, ByVal value As Person)
| > List.Insert(index, value)
| > End Sub
| >
| > Public Sub Remove(ByVal value As Person)
| > List.Remove(value)
| > End Sub
| >
| > Protected Overrides Sub OnValidate(ByVal value As Object)
| > If TypeOf value Is Person Then Return
| > Throw New InvalidCastException
| > End Sub
| >
| > End Class
| >
| > The OnValidate ensures that only Person objects are added to the
collection
| > when using the IList interface exposed by the collection...
| > CollectionBase.List (as above) uses the IList interface, while
| > CollectionBase.InnerList uses the contained (wrapped) ArrayList object.
| > Primarily InnerList.Add will not cause the OnValidate event to be
raised...
| >
| > In .NET 2.0 I would recommend inheriting from Collection(Of T).
| >
| > Public Class PersonCollection
| > Inherits System.Collections.ObjectModel.Collection(Of Person)
| >
| > End Class
| >
| > YES! that is all the code you need with .NET 2.0!
| >
| >
| > --
| > Hope this helps
| > Jay B. Harlow [MVP - Outlook]
| > ..NET Application Architect, Enthusiast, & Evangelist
| > T.S. Bradley - http://www.tsbradley.net
| >
| >
| > | > |I am converting (attempting) some vb6 code that makes vast use of
| > interfaces.
| > | One of the major uses is to be able to split out Read-only access to
an
| > | obect. Let me give you a simple (contrived) example:
| > | In Project RoObjDefs:
| > | RoPerson.cls file:
| > | Public Property Get FirstName() as String
| > | Public Property Get LastName() as String
| > | <end of file RoPerson.cls>
| > | RoPersons.cls file
| > | Public Function Count() as Integer
| > | Public Function Item(Index as Variant) as Person
| > | Public Function NewEnum() as IUnknown
| > | <end of file RoPersons.cls>
| > |
| > | Then in Project RwObjDefs:
| > | Person.cls file
| > | Implements RoObjDefs.RoPerson
| > | Private mFirstName as String
| > | Private mFirstName as String
| > | ...
| > | Public Property Get FirstName() as String
| > | FirstName = mFirstName
| > | End Property
| > | Public Property Set FirstName(byval val as string)
| > | mFirstName = val
| > | End Properety
| > | ...
| > | Private Property Get RoPerson_FirstName() as String
| > | RoPerson_FirstName = mFirstName
| > | End Property
| > | ...
| > | <end of Person.cls file>
| > |
| > | In file Persons.cls
| > | mPersons as collection
| > | ...(Code for add, item, remove, clear...)
| > | Public Function NewEnum() As IUnknown
| > | Set NewEnum = mPersons.[_NewEnum]
| > | End Function
| > | ...(implement the RO functions, like in Person class above)
| > | <end of Persons.cls>
| > |
| > | I could then 'cast' a Person to an RoPerson, when I only wanted to
give
| > out
| > | a readonly interface.
| > | I find when I attempt this that I can not do it though the use of
| > | interfaces. At least I cant if I want the properties to have the same
| > name
| > | on both of the interfaces.
| > | My guess is that I should now do this with inheritance. For example:
| > |
| > | Public Class RoPerson
| > | Protected mFirstName as string
| > | Public Readonly Property FirstName() as string
| > | Return mFirstName
| > | End Property
| > | ...
| > | and then in another class:
| > | Public Class Person
| > | Inherits RoPerson
| > | Public Shadows Property FirstName() As String
| > | Get
| > | Return MyBase.FirstName
| > | End Get
| > | Set(byval value as string)
| > | MyBase.mFirstName = value
| > | End Set
| > | ...
| > |
| > | Then like under VB6, I could 'cast' the object to its base when
returning
| > a
| > | reference to a readonly user.
| > | So, is this the best (only) way to accomplish what I was doing using
| > | interfaces in VB6? And, how do I implement 'enumeration' for my
custom
| > | collections in .Net? That is with out giving them remove, clear and
any
| > | other 'write' type functions that are implemented in the base class.
| > |
| > | Thanks in advance for your guidance.
| > | --
| > | Terry
| >
| >
| >
 
G

Guest

Hi Jay,
Thanks for the reply. I don't know if you had seen my subsequent post, I
had managed to make some progress on this issue. Thanks also for pointing
out the ReadOnlyBase (for generics), I had seen the ReadOnlyCollectionBase
and couldn't figure out why there wasn't one for generics...in fact it is
there but not in its proper place of the 'alphabetical' list of classes under
generics - someone needs to be reminded that 'R' comes before 'S'!
I have one further question (at least its only one at the moment). When
I finish converting these classes to VB.Net, they will need to be used by
..Net, VB6 and VBA (access) applications. How does that, if at all, affect my
choice of what collection class I should be using?

Thanks again - don't know what I would do without all your help!
--
Terry


Jay B. Harlow said:
Terry,
| Is the .Net equivalent of the VB6 collection object a
| System.Collections.Hashtable?
Microsoft.VisualBasic.Collection is .NET's equivalent to VB6's collection.
However I would not recommend using it as it normally does more then you
really want, plus it is 1 based as opposed to 0 based. 0 based collections
are prevalent in the Framework.

ArrayList & HashTable are .NET 1.x "common" collection's while List(Of T) &
Dictionary(Of T) are .NET 2.0 "common" collection.

By "common" I mean most versatile, where you would have used Collection in
VB6.

ArrayList & List(Of T) are used when you have an ordered collection of items
that do not have a key.

HashTable & Dictionary(Of T) are used when you have an unordered collection
of items that have a key.

CollectionBase, ReadOnlyCollectionBase and DictionaryBase are the .NET 1.x
way of doing things.
Collection(Of T), ReadonlyCollection(Of T), and KeyedCollection(Of T) are
the .NET 2.0 way of doing things.

NOTE: KeyedCollection(Of T) can be used for an ordered collection w/keys;
while DictionaryBase cannot.

| Is the .Net equivelant (for the generic case):
| Public Function GetEnumerator() as
| System.Collections.Generic.Dictionary.Enumerator
| return mPersons.GetEnumerator()
| end function
Yes call GetEnumerator is the equivelant, as I believe you found out. Be
careful some collections such as Dictionary(OF T) & HashTable are actually
collections of key/value pairs. Which means that the enumerator returns a
structure that contains both the key & the value. KeyedCollection(Of T)
returns an enumerator of just the value, as it is an IList(Of T) first, that
maintains a second collection of the keys...

--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Hi Jay,
| Thanks for the help!
|
| First, I had just spent several hours on a responce to you (along with
other
| things)and when I 'posted' it, I was taken back to the logon page and my
| entire response was lost! Is that normal? Is there a timeout on this
site
| or was it just a glitch?
|
| Ok, so I can use interfaces in the same way as I did in VB6. Guess I got
| off on the wrong foot when the IDE inserted public readonly properties
using
| the same name as soon as I typed in the Implements clasue. Thought I had
to
| leave the property names alone (as in VB6).
| As far as the custom collections go, I really would prefer NOT to expose
| 'Add', 'Remove', etc to the client objects. This is a commercial product
| and the API it exposes needs to be 'clean', and not contain methods and
| properties that they should not use.
| If I inherit from one of the base collection classes, then I will expose
all
| these methods. So, I wish to wrap one of the collection classes as I did
in
| VB6. Is the .Net equivalent of the VB6 collection object a
| System.Collections.Hashtable? And if I wanted to use a generic collection
| would I use a 'Dictionary' as the closest thing to the VB6 collection
type?
|
| In VB6 you provided 'enumeration' for your custom collections by including
| the following code in your class:
| Public Function NewEnum() As IUnknown
| Set NewEnum = mPersons.[_NewEnum]
| End Function
| and setting the ProcedureId to -4 (Under Procedure Attributes/Advanced)
| Is the .Net equivelant (for the generic case):
| Public Function GetEnumerator() as
| System.Collections.Generic.Dictionary.Enumerator
| return mPersons.GetEnumerator()
| end function
|
| Thanks again for all your help!!!
| --
| Terry
|
|
| "Jay B. Harlow [MVP - Outlook]" wrote:
|
| > Terry,
| > In addition to the other comments:
| >
| > | So, is this the best (only) way to accomplish what I was doing using
| > | interfaces in VB6?
| >
| > Rather then use Shadows & inheritance.
| >
| > I would recommend to use "explicit interface implementation" something
like:
| >
| > Public Interface IReadonlyPerson
| >
| > ReadOnly Property FirstName() As String
| > ReadOnly Property LastName() As String
| >
| > End Interface
| >
| > Public Class Person
| > Implements IReadonlyPerson
| >
| > Public Property FirstName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > Public Property LastName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > #Region " IReadonlyPerson support "
| >
| > Private ReadOnly Property IReadonlyPerson_FirstName() As String
| > Implements IReadonlyPerson.FirstName
| > Get
| > Return FirstName
| > End Get
| > End Property
| >
| > Private ReadOnly Property IReadonlyPerson_LastName() As String
| > Implements IReadonlyPerson.LastName
| > Get
| > Return LastName
| > End Get
| > End Property
| >
| > #End Region
| >
| > End Class
| >
| > Unfortunately any code that receives an IReadonlyPerson value can simply
| > cast it back to Person to gain full access to the object. If you want a
true
| > Readonly Person I would create a Readonly Person class that delegated
| > (wrapped) a Person object. Something like:
| >
| > Public Class ReadonlyPerson
| >
| > Private ReadOnly m_person As Person
| >
| > Public Sub New(ByVal person As Person)
| > m_person = person
| > End Sub
| >
| > Public ReadOnly Property FirstName() As String
| > Get
| > Return m_person.FirstName
| > End Get
| > End Property
| > Public ReadOnly Property LastName() As String
| > Get
| > Return m_person.LastName
| > End Get
| > End Property
| >
| > End Class
| >
| > Public Class Person
| >
| > Public Property FirstName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > Public Property LastName() As String
| > Get
| >
| > End Get
| > Set(ByVal value As String)
| >
| > End Set
| > End Property
| >
| > Public Function AsReadonly() As ReadonlyPerson
| > Return New ReadonlyPerson(Me)
| > End Function
| >
| > End Class
| >
| > Of course using Reflection one could break the contract with
ReadonlyPerson,
| > however that would be more effort...
| >
| > | And, how do I implement 'enumeration' for my custom
| > | collections in .Net? That is with out giving them remove, clear and
any
| > | other 'write' type functions that are implemented in the base class.
| > In .NET 1.x I would recommend inheriting from
| > System.Collections.CollectionBase:
| >
| > Public Class PersonCollection
| > Inherits System.Collections.CollectionBase
| >
| > Default Public Property Item(ByVal index As Integer) As Person
| > Get
| > Return DirectCast(List.Item(index), Person)
| > End Get
| > Set(ByVal value As Person)
| > List.Item(index) = value
| > End Set
| > End Property
| >
| > Public Sub Add(ByVal value As Person)
| > List.Add(value)
| > End Sub
| >
| > Public Function Contains(ByVal value As Person) As Boolean
| > Return List.Contains(value)
| > End Function
| >
| > Public Function IndexOf(ByVal value As Person) As Integer
| > Return List.IndexOf(value)
| > End Function
| >
| > Public Sub Insert(ByVal index As Integer, ByVal value As Person)
| > List.Insert(index, value)
| > End Sub
| >
| > Public Sub Remove(ByVal value As Person)
| > List.Remove(value)
| > End Sub
| >
| > Protected Overrides Sub OnValidate(ByVal value As Object)
| > If TypeOf value Is Person Then Return
| > Throw New InvalidCastException
| > End Sub
| >
| > End Class
| >
| > The OnValidate ensures that only Person objects are added to the
collection
| > when using the IList interface exposed by the collection...
| > CollectionBase.List (as above) uses the IList interface, while
| > CollectionBase.InnerList uses the contained (wrapped) ArrayList object.
| > Primarily InnerList.Add will not cause the OnValidate event to be
raised...
| >
| > In .NET 2.0 I would recommend inheriting from Collection(Of T).
| >
| > Public Class PersonCollection
| > Inherits System.Collections.ObjectModel.Collection(Of Person)
| >
| > End Class
| >
| > YES! that is all the code you need with .NET 2.0!
| >
| >
| > --
| > Hope this helps
| > Jay B. Harlow [MVP - Outlook]
| > ..NET Application Architect, Enthusiast, & Evangelist
| > T.S. Bradley - http://www.tsbradley.net
| >
| >
| > | > |I am converting (attempting) some vb6 code that makes vast use of
| > interfaces.
| > | One of the major uses is to be able to split out Read-only access to
an
| > | obect. Let me give you a simple (contrived) example:
| > | In Project RoObjDefs:
| > | RoPerson.cls file:
| > | Public Property Get FirstName() as String
| > | Public Property Get LastName() as String
| > | <end of file RoPerson.cls>
| > | RoPersons.cls file
| > | Public Function Count() as Integer
| > | Public Function Item(Index as Variant) as Person
| > | Public Function NewEnum() as IUnknown
 
L

Linda Liu [MSFT]

Hi Terry,
"I also came accross a 'ReadOnlyCollectionBase' that "Provides the
abstract base class for a strongly typed non-generic read-only collection."
This statement confuses me - thought that, by definition, non-generic
collections are considered to NOT be strongly typed. "

The ReadOnlyCollectionBase is an abstract base class for a strongly typed
non-generic read-only colletion. It means that the elements in the
ReadOnlyCollectionBase are of the same type and the type is predefined by
the implementation class of the ReadOnlyCollectionBase and not determined
by the user of the collection.

And the generic version of the ReadOnlyCollectionBase class is the
ReadOnlyCollection class which is located in the namespace
System.Collections.ObjectModel.
When I finish converting these classes to VB.Net, they will need to be used by
.Net, VB6 and VBA (access) applications. How does that, if at all, affect my
choice of what collection class I should be using?

You can use any of the collection classes in .Net. There's no limitation.

Hope this is helpful to you.
If you have any concerns or need anything else, please don't hesitate to
let me know.



Sincerely,
Linda Liu
Microsoft Online Community Support

====================================================
When responding to posts,please "Reply to Group" via
your newsreader so that others may learn and benefit
from your issue.
====================================================
 

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