convert one generic collection to another

piggybank1974
01-23-2010, 07:00 AM
Hi There,

I've stumped myself, mental block today it must be!

I have the below code and it works fine, it's this way because I need to manually calculate some data before adding it to the Listview control.


Dim mList As List(Of ListViewItem) = mDataBase.GetRecords(LvwChecks, "CheckGroups", <Query>, GetType(CheckItem))
If mList.Count > 0 Then
Me.LvwChecks.AddRange(mList.ToArray())
End If


What I want to do is basically this List(Of ListViewItem) to List(Of CheckItem)

Like this but it does not work!

Dim mList As List(Of CheckItem) = CType(mDataBase.GetRecords(LvwChecks, "CheckGroups", <Query>, GetType(CheckItem)), List(Of CheckItem))


this is so I can edit whatever i want, instead of maually having to type cast it e.g


Dim mCheckItem as CheckItem = CType(mList(<Index>), CheckItem)

hawkvalley1
01-23-2010, 07:50 AM
My guess is it has something to do with the return value from the GetRecords function. Without seeing more code this is just a stab in the dark.

piggybank1974
01-23-2010, 11:19 AM
Yeah your correct it returns a List(Of Listviewitem) but I want to cast that to a inherited type List(Of CheckItem) (CheckItem inherits from ListviewItem)

AtmaWeapon
01-23-2010, 11:36 AM
You can't, unfortunately, but .NET 4 might change that.

There's two fancy words related to this: "contravariance" and "covariance". I can never remember which is which, but one describes this situation. Let's call the correct word "foo". In a language that supports foo, you can cast from one generic type to another if casting of its type parameters would work. I'm assuming that CheckItem is some custom ListViewItem-derived type. If this is so, then if VB .NET supported foo then you could do it. Unfortunately it doesn't. I know that C# 4 is getting some limited contravariance and covariance features, but I'm unclear as to whether VB .NET will get any of them as well.

So what you'll be stuck with is a conversion function:

Function Convert(ByVal items As List(Of ListViewItem)) As List(Of CheckItem)
Dim newList As New List(Of CheckItem)()
For Each item As ListViewItem in items
newList.Add(CType(item, CheckItem))
Next
Return newList
End Function

If that cast would fail anyway I'm not sure why there'd be an expectation that the list types are compatible; this is why I'm assuming the cast is valid.

piggybank1974
01-23-2010, 11:58 AM
Cheers AW,

All I can say is 'Foo' with several letters added to it that I cannot post :) As I said it's not to much of a problem I just thought it would make it neater!

I'm assuming that CheckItem is some custom ListViewItem-derived type

Yeah your correct as usual ;) my database class has a few clever methods of which GetRecords it just one of them it bascially fills a listviewitem and public properties (I add these to an inherited ListviewItem) in one go.

It's so much easier working with property names than indexes as errors can ocrrure.

the trouble with this one is I needed to add some time calculations on a certain field (Subitem), that is not connected to the database record, I though If I could convert it easily I could swaping in what I want(<Object>.Items.SubItems(<Index>).Text = <Text>) and then add it as a range as normal.

Thanks anyways!

snarfblam
01-23-2010, 12:19 PM
You could very easily create a wrapper which performs the cast. You could even create a generic wrapper so that you will always be able to "convert" on list type to another. But you will always run the risk of a runtime exception if items in the original list are not convertible to the type of the "converted" list.



''' <summary>
''' Wraps a IList(Of T) as a list of a derived type
''' </summary>
Public Class ListWrapper(Of TSource, TNewType As TSource)
Implements IList(Of TNewType)

Public Sub New(ByVal source As IList(Of TSource))
Me.sourceList = source
End Sub
Dim sourceList As IList(Of TSource)

Public Sub Add(ByVal item As TNewType) Implements IList(Of TNewType).Add
sourceList.Add(DirectCast(item, TSource))
End Sub

Public Property Items(index as Integer) As TNewType
Get
Return sourceList(index)
End Get
Set(ByVal value As TNewType)
sourceList(index) = DirectCast(value, TNewType)
End Set
End Property

'ect...
End Class


Now we can type Dim myList As IList(Of CheckItem) = New ListWrapper(Of ListViewItem, CheckItem)(someListView.Items). You can continue to reuse this collection as a stand-in for the original.

Also, piggy, you need to break up those long lines. They are messing up the forum, never mind making the code unreadable.

piggybank1974
01-23-2010, 12:30 PM
Hi marble_eater,

Yeah I've changed it in the forum(<Query>) should of done it sooner sorry ADMIN.

I'm not saying I could not create a wrapper, but for one it's pointless the extra code is overkill I think! It only displays a max of 14 items depending on what Welfare checks have to be made, and is only used on this form alone.

I dont want to burst you bubble and nice idea and thanks again.

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum