![]() |
|
|
|||||||
![]() |
|
|
LinkBack | Thread Tools | Search this Thread | Display Modes |
|
|||
|
Implement IEnumerable(Of T) and Inherit from CollectionBase
A base Class in a framework looks thusly
Public MustInherit Class BindableCollectionBase(Of T As IBusinessBase) Inherits CollectionBase Implements IBindingList I want to implement the IEnumerable(Of T) as well. Everything I have tried leads to either stackoverflow or invalid cast exceptions. How do I implement the generic IEnumerable(Of T) and also inherit from the CollectinoBase? I cannot, at this time, switch to inheriting the Collection(Of T) class because this is a base class in a framework and doing so would cause much craziness. |
|
|||
|
RE: Implement IEnumerable(Of T) and Inherit from CollectionBase
I think I got it working but not real happy with the implementation. It seems
like there would be some performance issues. Any better ideas? Or, more importantly, will this actually work? Public MustInherit Class BindableCollectionBase(Of T As IBusinessBase) Inherits CollectionBase Implements IBindingList Implements System.Collections.Generic.IEnumerable(Of T) Public Function GetEnumerator1() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator Dim lst As New List(Of T) For Each item As T In Me lst.Add(item) Next Return New BindableBaseEnumerator(Of T)(lst) 'CType(MyBase.GetEnumerator, Global.System.Collections.Generic.IEnumerator(Of T)) End Function ..... End Class Public Class BindableBaseEnumerator(Of T As IBusinessBase) Implements IEnumerator(Of T) Public ReadOnly Property Current() As T Implements System.Collections.Generic.IEnumerator(Of T).Current Get Try Return lvLst(position) Catch ex As Exception Throw (New InvalidOperationException()) End Try End Get End Property Public ReadOnly Property Current1() As Object Implements System.Collections.IEnumerator.Current Get Try Return lvLst(position) Catch ex As Exception Throw (New InvalidOperationException()) End Try End Get End Property Dim position As Integer = -1 Private lvLst As List(Of T) Public Sub New(ByVal list As List(Of T)) lvLst = list End Sub Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext position = position + 1 Return (position < lvLst.Count) End Function Public Sub Reset() Implements IEnumerator.Reset position = -1 End Sub Private disposedValue As Boolean = False ' To detect redundant calls ' IDisposable Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' TODO: free other state (managed objects). End If ' TODO: free your own state (unmanaged objects). ' TODO: set large fields to null. End If Me.disposedValue = True End Sub #Region " IDisposable Support " ' This code added by Visual Basic to correctly implement the disposable pattern. Public Sub Dispose() Implements IDisposable.Dispose ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region End Class |
|
|||
|
Re: Implement IEnumerable(Of T) and Inherit from CollectionBase
Paul Linville wrote:
> A base Class in a framework looks thusly > > Public MustInherit Class BindableCollectionBase(Of T As IBusinessBase) > Inherits CollectionBase > Implements IBindingList > > > I want to implement the IEnumerable(Of T) as well. Everything I have tried > leads to either stackoverflow or invalid cast exceptions. > > How do I implement the generic IEnumerable(Of T) and also inherit from the > CollectinoBase? I cannot, at this time, switch to inheriting the > Collection(Of T) class because this is a base class in a framework and doing > so would cause much craziness. Well, this should work: Public Overloads Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator ... End Function The problem is filling in the "...", of course. If BindableCollectionBase does not implement IEnumerator(Of T), you cannot defer to a base class implementation to get the desired enumerator, since there isn't any -- the non-generic enumerators aren't good enough. You can use a wrapper class for this purpose: Public Structure GenericEnumeratorAdapter(Of T) Implements IEnumerator(Of T) Private Inner As IEnumerator Public Sub New(ByVal Inner As IEnumerator) Me.Inner = Inner End Sub Public ReadOnly Property Current() As T Implements IEnumerator(Of T).Current Get Return CType(Inner.Current, T) End Get End Property Private ReadOnly Property UntypedCurrent() As Object Implements IEnumerator.Current Get Return Inner.Current End Get End Property Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext Return Inner.MoveNext End Function Public Sub Reset() Implements IEnumerator.Reset Inner.Reset() End Sub Public Sub Dispose() Implements IDisposable.Dispose CType(Inner, IDisposable).Dispose() End Sub End Structure Now it's a simple matter of writing: Public Overloads Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator Return New GenericEnumeratorAdapter(Of T)(MyBase.GetEnumerator) End Function -- J. |
|
|||
|
Re: Implement IEnumerable(Of T) and Inherit from CollectionBase
Ahhh. Perfect. Much better than my solution.
Thank you very much. "Jeroen Mostert" wrote: > Paul Linville wrote: > > A base Class in a framework looks thusly > > > > Public MustInherit Class BindableCollectionBase(Of T As IBusinessBase) > > Inherits CollectionBase > > Implements IBindingList > > > > > > I want to implement the IEnumerable(Of T) as well. Everything I have tried > > leads to either stackoverflow or invalid cast exceptions. > > > > How do I implement the generic IEnumerable(Of T) and also inherit from the > > CollectinoBase? I cannot, at this time, switch to inheriting the > > Collection(Of T) class because this is a base class in a framework and doing > > so would cause much craziness. > > Well, this should work: > > Public Overloads Function GetEnumerator() As IEnumerator(Of T) Implements > IEnumerable(Of T).GetEnumerator > ... > End Function > > The problem is filling in the "...", of course. If BindableCollectionBase > does not implement IEnumerator(Of T), you cannot defer to a base class > implementation to get the desired enumerator, since there isn't any -- the > non-generic enumerators aren't good enough. You can use a wrapper class for > this purpose: > > Public Structure GenericEnumeratorAdapter(Of T) > Implements IEnumerator(Of T) > > Private Inner As IEnumerator > Public Sub New(ByVal Inner As IEnumerator) > Me.Inner = Inner > End Sub > > Public ReadOnly Property Current() As T Implements IEnumerator(Of > T).Current > Get > Return CType(Inner.Current, T) > End Get > End Property > > Private ReadOnly Property UntypedCurrent() As Object Implements > IEnumerator.Current > Get > Return Inner.Current > End Get > End Property > > Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext > Return Inner.MoveNext > End Function > > Public Sub Reset() Implements IEnumerator.Reset > Inner.Reset() > End Sub > > Public Sub Dispose() Implements IDisposable.Dispose > CType(Inner, IDisposable).Dispose() > End Sub > End Structure > > Now it's a simple matter of writing: > > Public Overloads Function GetEnumerator() As IEnumerator(Of T) Implements > IEnumerable(Of T).GetEnumerator > Return New GenericEnumeratorAdapter(Of T)(MyBase.GetEnumerator) > End Function > > -- > J. > |
|
|||
|
Re: Implement IEnumerable(Of T) and Inherit from CollectionBase
Paul Linville wrote:
> I think I got it working but not real happy with the implementation. It seems > like there would be some performance issues. > > Any better ideas? Or, more importantly, will this actually work? > > > Public MustInherit Class BindableCollectionBase(Of T As IBusinessBase) > Inherits CollectionBase > Implements IBindingList > > > Implements System.Collections.Generic.IEnumerable(Of T) > Public Function GetEnumerator1() As > System.Collections.Generic.IEnumerator(Of T) Implements > System.Collections.Generic.IEnumerable(Of T).GetEnumerator > Dim lst As New List(Of T) > For Each item As T In Me > lst.Add(item) > Next > Well, yes, if you allocate a new list for every iteration there *will* be performance issues... There's no need for that. See my previous post. <snip> > Public ReadOnly Property Current() As T Implements > System.Collections.Generic.IEnumerator(Of T).Current > Get > Try > Return lvLst(position) > Catch ex As Exception > Throw (New InvalidOperationException()) > End Try > This is poor style (no pun intended). First, do not catch the general type Exception -- you can't do anything meaningful with it except perhaps at the outermost level of your application, where you could log it. If for example the framework threw an OutOfMemoryException or a ThreadAbortException here, you would not want to mask this by throwing an InvalidOperationException. Second, there is no point here to catching exceptions at all, because you know exactly when the error should occur: when .MoveNext() hasn't been called after creation or after .Reset(), or the last call to .MoveNext() returned false. In this case, this all translates to "position" being valid. Relying on List to throw an ArgumentOutOfRangeException for you can mask errors and false assumptions, and they obfuscate the conditions under which your code can and should fail. Here, it isn't likely that List contains a bug, or that it will one day not throw ArgumentOutOfRangeException, or that it will one day throw something else, but in general it's unwise to depend on exact error behavior as you're doing here. It's a simple matter of implementing the checks yourself so you don't introduce the dependency in the first place. This seems like a long sermon for a short bit of throwaway code, but I see this sort of thing all the time and I'm usually the unlucky schmuck who has to fix the resulting code, so I figure that spreading the word as much as possible may make someone's life a tiny bit happier... -- J. |
|
|||
|
Re: Implement IEnumerable(Of T) and Inherit from CollectionBase
On Jul 9, 5:37*pm, Paul Linville
<PaulLinvi...@discussions.microsoft.com> wrote: > A base Class in a framework looks thusly > > * * Public MustInherit Class BindableCollectionBase(Of T As IBusinessBase) > * * * * Inherits CollectionBase > * * * * Implements IBindingList > > I want to implement the IEnumerable(Of T) as well. Everything I have tried > leads to either stackoverflow or invalid cast exceptions. > > How do I implement the generic IEnumerable(Of T) and also inherit from the > CollectinoBase? *I cannot, at this time, switch to inheriting the > Collection(Of T) class because this is a base class in a framework and doing > so would cause much craziness. If you're using .NET 3.5, the simplest would be to do this: Private Function GetEnumerator1() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator Return Me.Cast(Of T)().GetEnumerator() End Function You can probably also use that code with LINQbridge on .NET 2.0/3.0 |
![]() |
|
| Thread Tools | Search this Thread |
| Display Modes | |
|
|