views:

55

answers:

3

I'm using a LINQ query to translate data inside a DataTable object to be a simple IEnumerable of a custom POCO object.

My LINQ query is:

    Dim dtMessages As DataTable

    '...dtMessages is instantiated ByRef in a helper data access routine... '

    Dim qry = From dr As DataRow In dtMessages.Rows
              Select New OutboxMsg With {
                  .ComputerID = dr(dcComputerID),
                  .MessageData = dr(dcMessageData),
                  .OutBoxID = dr(dcOutBoxID),
                  .OutBoxReceivedID = dr(dcOutBoxReceivedID),
                  .TrxDate = dr(dcTrxDate)
              }

However, the compiler is throwing a warning message under dr As DataRow with the message:

Option Strict On disallows implicit conversions from 'Object' to 'System.Data.DataRow'.

Why am I getting this error and what do I need to do to fix it? I would have thought that dtMessages.Rows returned a collection of type DataRow. Is this not correct?

+5  A: 

The type System.DataTable predates generics in .Net and hence returns a plain old IEnumerable instead of an IEnumerable(Of DataRow) even though under the hood they are instances of DataRow. Hence the type of dr in the above query is Object and not DataRow.

You can work around this by using the Cast extension method to make the type of the collection explicit

From dr As DataRow in dtMessages.Rows.Cast(Of DataRow)
JaredPar
+5  A: 

Lok at DataTable.Rows - it's a DataRowCollection which only implements IEnumerable, not IEnumerable(Of DataRow).

Fortunately, there's an extension method in DataTableExtensions which lets you call AsEnumerable() instead of Rows; AsEnumerable returns an IEnumerable(Of DataRow):

Dim qry = From dr As DataRow In dtMessages.AsEnumerable()
          ...

(I prefer this over using dt.Rows.Cast(Of DataRow), as it gives less of an impression of something which might fail. It's more tailored to DataTable. Both will work though.)

Jon Skeet
+2  A: 

The DataTable.Rows property returns a collection of DataRow, however that collection doesn't implement IEnumerable<DataRow> but IEnumerable, which works as IEnumerable<Object>.

You can explicitly cast the collection items to DataRow using dtMessages.Rows.Cast<DataRow>().

Guffa