1

I'm trying to use Linq to push DataColumn values into a ListControl. My Linq code is as follows:

ddl_listControl.Items.AddRange(
    From dr As DataRow In ds.Tables(0).Row Select New ListItem(
        dr.Item("Value").ToString(), 
        dr.Item("ID").ToString()
    )
)

Unable to cast object of type 'WhereSelectEnumerableIterator`2[System.Object,System.Web.UI.WebControls.ListItem]' to type 'System.Web.UI.WebControls.ListItem[]'.

Can anyone please advise on how to correct the Linq?

Answer

Based on Tim's input, I used:

ddl_regionSelected.Items.AddRange((From dr As DataRow In ds.Tables(0).Rows Select New ListItem(dr.Item("regionName").ToString(), dr.Item("ID").ToString())).ToArray())

Or for those who love C# styling so much...(!)

ddl_regionSelected.Items.AddRange((From dr As DataRow In ds.Tables(0).Rows
                                           Select New ListItem(
                                               dr.Item("regionName").ToString(),
                                               dr.Item("ID").ToString())
                                           ).ToArray())

The part I missed was to wrap the whole Linq statement in braces, then cast to result .ToArray()

EvilDr
  • 8,943
  • 14
  • 73
  • 133

1 Answers1

1

ListItemCollection.AddRange accepts only a ListItem[] so use:

Dim items = From rom In ds.Tables(0).AsEnumerable() 
            Select New ListItem(dr.Item("Value").ToString(),dr.Item("ID").ToString())
ddl_listControl.Items.AddRange(items.ToArray())

or a simple loop which does not need that new array:

For Each item As ListItem in items 
    ddl_listControl.Items.Add(item)
Next

I like this mixture of query- and method syntax more in VB.NET than pure method syntax because of the ugly function keyword. However, here it is:

Dim items As ListItem() = ds.Tables(0).AsEnumerable().
    Select(Function(dr) New ListItem(dr.Item("Value").ToString(),dr.Item("ID").ToString())).
    ToArray() 

This is not more efficient even if it's (technically) a single statement.

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • I was using Linq to replace the `For Each` approach. I *can* get it to one line by wrapping in braces then casting `.ToArray()` which works well. Thanks for the pointer! I updated the question with the one-line solution based on your input. – EvilDr Jan 21 '15 at 15:57
  • We don't need that *ugly* `Function()` after all :-) – EvilDr Jan 21 '15 at 16:08
  • 1
    @EvilDr: yes, you can use parentheses. However, i don't like them either. Just another source of nasty errors, they are also making it more difficult to read. So remove them and use another line. Due to LINQ's deferred execution it's taking the same time but is much more readable and maintainable. It's also easier to debug since you can always execute the query with `items.ToArray` if you set a breakpoint at `...AddRange` – Tim Schmelter Jan 21 '15 at 16:15
  • You've used `ToArray`, but does it matter whether you opt for that, or `ToList` or `ToDictionary` etc. They all implement IEnumerable so I assume it doesn't matter, but is any method most suitable? – EvilDr Jan 29 '15 at 15:22
  • @EvilDr: I'm afraid that i don't understand the question. You have to use `ToArray` here because [`ListItemCollection.AddRange`](https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listitemcollection.addrange(v=vs.110).aspx) accepts only a `ListItem[]` and not `IEnumerable`. You could also omit the `ToArray` and use a `For Each`-loop to add the items via [`ListItemCollection.Add`](https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listitemcollection.add(v=vs.110).aspx) one at a time. Use what you need, premature optimization is the root of all evil :) – Tim Schmelter Jan 29 '15 at 15:39
  • Sorry Tim. I meant that you used `ToArray` in your solution, but `ToList` also works, so does it matter which one is used? – EvilDr Jan 29 '15 at 22:22
  • 1
    @EvilDr: you cannot use `ToList` because that creates a `List` which cannot be used in [`ListItemCollection.AddRange`](https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listitemcollection.addrange(v=vs.110).aspx). – Tim Schmelter Jan 29 '15 at 22:26