|
Recently I had the need to implements some remoting solutions and I ran into a problem. After googling around a bit, I confirmed that the .NET Framework does not provide you with a remoting-compatible collection (if someone knows of one, please let me know). So I went about writing one. I wanted a strongly typed collection which I used to achieve by inheriting from CollectionBase and adding the strongly typed implementation. In 2.0, I started inheriting from the List<T> generic collection which was even better. The problem is that neither of these two objects inherit from MarshalByRefObject, which is required for remoting solutions.
My solution was to create a new class (BusinessCollectionBase), accept a generic for the kind of object it will contain (TBusinessObject), and add a protected property as type List<TBusinessObject>. This class inherits from MarshalByRefObject which makes it usable in a remoting situation. Now, the trick was to expose everything I had to and map it to the internal list. The trick to doing this is to implement all the correct interfaces and perform the mapping there. This way, any collection object you create that inherits from this class will have all the necessary enumeration and binding compatibility of any standard collection (this is the luxury we got inheriting from CollectionBase or DictionaryBase in the past, or one of the generic collections now).
The result is listed below. Notice the implementation of both the generic- nterfaces and the non-generic interfaces. This is very important for the collection to be both strongly typed and bindable to visual controls. Also notice that the implementations of the non-generic interfaces have been changed to Protected, as opossed to the default Public. They are only needed for the data binding compatibility where the control doing the binding is casting to the appropriate interface anyway. The generic-compatible implementations are the only thing I want to expose because they provide the strong typing.
You can of course alter this to accomodate any type of collection you want. In this case I used a List<T>, but you can contain anything that suits your needs.
Also, notice that I added a couple of methods for the class to support serialization. Though usually tagging it “Serializable“ is all that is necessary, with these methods, you can actually return a string representation of your collection so you can put it into a cookie, if you're using it on the web.
If anyone further modifies or enhances this, I'd love to hear about it.
Imports System Imports System.Collections Imports System.Collections.Generic Imports System.Xml.Serialization
Namespace InfoTek.Business
Public MustInherit Class BusinessCollectionBase(Of TBusinessObject As New)
Inherits MarshalByRefObject Implements IList(Of TBusinessObject) Implements IList Implements ICollection(Of TBusinessObject) Implements ICollection Implements IEnumerable(Of TBusinessObject) Implements IEnumerable
Protected innerList As List(Of TBusinessObject) = New List(Of TBusinessObject)
Public Function Add() As TBusinessObject Dim o_Item As TBusinessObject = New TBusinessObject() innerList.Add(o_Item) Return o_Item End Function
Public Function SerializeObject() As String Dim o_MemStream As MemoryStream = New MemoryStream Dim o_Serializer As XmlSerializer = New XmlSerializer(Me.GetType()) o_Serializer.Serialize(o_MemStream, Me) Return ASCII.GetString(o_MemStream.ToArray()) End Function
Public Function DeserializeObject(ByVal xmlString As String) As Object Dim o_Serializer As XmlSerializer = New XmlSerializer(Me.GetType()) Dim o_MemStream As MemoryStream = New MemoryStream(ASCII.GetBytes(xmlString)) Return o_Serializer.Deserialize(o_MemStream) End Function
#Region "ICollection(Of TBusinessObject) implementation"
Public Sub Add(ByVal item As TBusinessObject) Implements System.Collections.Generic.ICollection(Of TBusinessObject).Add CType(innerList, ICollection(Of TBusinessObject)).Add(item) End Sub
Public Sub Clear() Implements System.Collections.Generic.ICollection(Of TBusinessObject).Clear CType(innerList, ICollection(Of TBusinessObject)).Clear() End Sub
Public Function Contains(ByVal item As TBusinessObject) As Boolean Implements System.Collections.Generic.ICollection(Of TBusinessObject).Contains Return CType(innerList, ICollection(Of TBusinessObject)).Contains(item) End Function
Public Sub CopyTo(ByVal array() As TBusinessObject, ByVal arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of TBusinessObject).CopyTo CType(innerList, ICollection(Of TBusinessObject)).CopyTo(array, arrayIndex) End Sub
Public ReadOnly Property Count() As Integer Implements System.Collections.Generic.ICollection(Of TBusinessObject).Count Get Return CType(innerList, ICollection(Of TBusinessObject)).Count End Get End Property
Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.Generic.ICollection(Of TBusinessObject).IsReadOnly Get Return CType(innerList, ICollection(Of TBusinessObject)).IsReadOnly End Get End Property
Public Function Remove(ByVal item As TBusinessObject) As Boolean Implements System.Collections.Generic.ICollection(Of TBusinessObject).Remove Return CType(innerList, ICollection(Of TBusinessObject)).Remove(item) End Function
#End Region
#Region "IEnumerable(Of TBusinessObject) implementation"
Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of TBusinessObject) Implements System.Collections.Generic.IEnumerable(Of TBusinessObject).GetEnumerator Return CType(innerList, IEnumerable(Of TBusinessObject)).GetEnumerator() End Function
#End Region
#Region "IList(Of TBusinessObject) implementation"
Public Function IndexOf(ByVal item As TBusinessObject) As Integer Implements System.Collections.Generic.IList(Of TBusinessObject).IndexOf Return CType(innerList, IList(Of TBusinessObject)).IndexOf(item) End Function
Public Sub Insert(ByVal index As Integer, ByVal item As TBusinessObject) Implements System.Collections.Generic.IList(Of TBusinessObject).Insert CType(innerList, IList(Of TBusinessObject)).Insert(index, item) End Sub
Default Public Property Item(ByVal index As Integer) As TBusinessObject Implements System.Collections.Generic.IList(Of TBusinessObject).Item Get Return CType(innerList, IList(Of TBusinessObject)).Item(index) End Get Set(ByVal value As TBusinessObject) CType(innerList, IList(Of TBusinessObject)).Item(index) = value End Set End Property
Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.Generic.IList(Of TBusinessObject).RemoveAt CType(innerList, IList(Of TBusinessObject)).RemoveAt(index) End Sub
#End Region
#Region "IEnumerable implementation"
Protected Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator Return CType(innerList, IEnumerable).GetEnumerator() End Function
#End Region
#Region "ICollection implementation"
Protected Sub CopyTo1(ByVal array As System.Array, ByVal index As Integer) Implements System.Collections.ICollection.CopyTo CType(innerList, ICollection).CopyTo(array, index) End Sub
Protected ReadOnly Property Count1() As Integer Implements System.Collections.ICollection.Count Get Return CType(innerList, ICollection).Count End Get End Property
Protected ReadOnly Property IsSynchronized() As Boolean Implements System.Collections.ICollection.IsSynchronized Get Return CType(innerList, ICollection).IsSynchronized End Get End Property
Protected ReadOnly Property SyncRoot() As Object Implements System.Collections.ICollection.SyncRoot Get Return CType(innerList, ICollection).SyncRoot End Get End Property
#End Region
#Region "IList implementation"
Protected Function Add1(ByVal value As Object) As Integer Implements System.Collections.IList.Add Return CType(innerList, IList).Add(value) End Function
Protected Sub Clear1() Implements System.Collections.IList.Clear CType(innerList, IList).Clear() End Sub
Protected Function Contains1(ByVal value As Object) As Boolean Implements System.Collections.IList.Contains Return CType(innerList, IList).Contains(value) End Function
Protected Function IndexOf1(ByVal value As Object) As Integer Implements System.Collections.IList.IndexOf Return CType(innerList, IList).IndexOf(value) End Function
Protected Sub Insert1(ByVal index As Integer, ByVal value As Object) Implements System.Collections.IList.Insert CType(innerList, IList).Insert(index, value) End Sub
Protected ReadOnly Property IsFixedSize() As Boolean Implements System.Collections.IList.IsFixedSize Get Return CType(innerList, IList).IsFixedSize End Get End Property
Protected ReadOnly Property IsReadOnly1() As Boolean Implements System.Collections.IList.IsReadOnly Get Return CType(innerList, IList).IsReadOnly End Get End Property
Protected Property Item1(ByVal index As Integer) As Object Implements System.Collections.IList.Item Get Return CType(innerList, IList).Item(index) End Get Set(ByVal value As Object) CType(innerList, IList).Item(index) = value End Set End Property
Protected Sub Remove1(ByVal value As Object) Implements System.Collections.IList.Remove CType(innerList, IList).Remove(value) End Sub
Protected Sub RemoveAt1(ByVal index As Integer) Implements System.Collections.IList.RemoveAt CType(innerList, IList).RemoveAt(index) End Sub
#End Region
End Class
End Namespace
|