|
web
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
converting the use of interfaces under vb6 to vb.netOne 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 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 Show quoteHide quote "Terry" <Terry@nospam.nospam> schreef in bericht news:6453F48A-457D-4D64-8EF7-061B050F5B77@microsoft.com... >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 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. ==================================================== 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 Show quoteHide quote "Linda Liu [MSFT]" wrote: > 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. > ==================================================== > > Terry,
In addition to the other comments: | So, is this the best (only) way to accomplish what I was doing using Rather then use Shadows & inheritance.| interfaces in VB6? 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 In .NET 1.x I would recommend inheriting from | collections in .Net? That is with out giving them remove, clear and any | other 'write' type functions that are implemented in the base class. 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! -- Show quoteHide quoteHope this helps Jay B. Harlow [MVP - Outlook] ..NET Application Architect, Enthusiast, & Evangelist T.S. Bradley - http://www.tsbradley.net "Terry" <Terry@nospam.nospam> wrote in message news:6453F48A-457D-4D64-8EF7-061B050F5B77@microsoft.com... |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 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!!! -- Show quoteHide quoteTerry "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 > > > "Terry" <Terry@nospam.nospam> wrote in message > news:6453F48A-457D-4D64-8EF7-061B050F5B77@microsoft.com... > |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 > > > Terry,
| Is the .Net equivalent of the VB6 collection object a Microsoft.VisualBasic.Collection is .NET's equivalent to VB6's collection. | System.Collections.Hashtable? 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): Yes call GetEnumerator is the equivelant, as I believe you found out. Be | Public Function GetEnumerator() as | System.Collections.Generic.Dictionary.Enumerator | return mPersons.GetEnumerator() | end function 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... -- Show quoteHide quoteHope this helps Jay B. Harlow [MVP - Outlook] ..NET Application Architect, Enthusiast, & Evangelist T.S. Bradley - http://www.tsbradley.net "Terry" <Terry@nospam.nospam> wrote in message news:0A87B568-B561-43B2-8F63-4ED51AD5575E@microsoft.com... | 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 | > | > | > "Terry" <Terry@nospam.nospam> wrote in message | > news:6453F48A-457D-4D64-8EF7-061B050F5B77@microsoft.com... | > |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 | > | > | > 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! -- Show quoteHide quoteTerry "Jay B. Harlow [MVP - Outlook]" wrote: > 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 > > > "Terry" <Terry@nospam.nospam> wrote in message > news:0A87B568-B561-43B2-8F63-4ED51AD5575E@microsoft.com... > | 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 > | > > | > > | > "Terry" <Terry@nospam.nospam> wrote in message > | > news:6453F48A-457D-4D64-8EF7-061B050F5B77@microsoft.com... > | > |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 Hi Terry,
>"I also came accross a 'ReadOnlyCollectionBase' that "Provides the The ReadOnlyCollectionBase is an abstract base class for a strongly typed >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. " 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 You can use any of the collection classes in .Net. There's no limitation.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? 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. ==================================================== 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. -- Show quoteHide quoteTerry "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 > > > "Terry" <Terry@nospam.nospam> wrote in message > news:6453F48A-457D-4D64-8EF7-061B050F5B77@microsoft.com... > |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 > > >
WebBrowser Control Frame Documents
Wrapper classes Windows Service using VB.Net automatic startup problem ! error handle preventing default value in vb.net How to translate C++ 'for' loop into VB.NET? ClickOnce deployment problem! make a form shared - called from another form - how? catch the process terminate from the task manager Best Suite Documentation |
|||||||||||||||||||||||