In C#, why does a datatable not know the type collection of rows?
I have recently started .NET programming, and looked at both VB.NET and C#. In VB.NET, a strongly typed Datatable cosisted of a collection of strongly types rows. Therefore, for example, this statement would work:
lCustomerTable As CustomerDataSet.CustomerTable
lCustomerRow as CustomerDataSet.CustomerTable.CustomerRow
lCustomerTable = TableAdapter.GetData
lCustomerRow = lCustomerTable.Rows(0)
However in C#, it seems i have to explicitly cast the returned Row to a CustomerRow:
lCustomerRow = (CustomerDataSet.CustomerTable.CustomerRow)lCustomerTable.Rows[0]
Is there any reason for this? Should the dataset not create the object type definitions when creating the table adapters 开发者_Go百科and SQL dataTables?
I don't think Rows
is actually strongly typed, even for typed datasets. The difference is that VB, by default, permits implicit downcasts. E.g. you can write:
Dim o As Object = ""
Dim s As String
s = o ' implicit downcast from Object to String!
This is only disabled if you use Option Strict
- try that in VB and see if your code still compiles...
In C#, the downcasts must always be explicit - it doesn't have a "non-strict mode".
Pavel is correct about the result you are seeing being because it is a narrowing conversion. However, casting is NOT the answer.
The Rows property is defined in the DataTable class, and is a DataRowCollection. However, there is a property defined in the strongly typed DataTable that handles returning the strongly typed rows.
In VB.Net:
Public Default ReadOnly Property Item(ByVal index As Integer) As CustomerRow
Get
Return CType(Me.Rows(index), CustomerRow)
End Get
End Property
In C#:
public CustomerRow this[int index] {
get {
return ((CustomerRow)(this.Rows[index]));
}
}
As you can see, it is still casting the rows, but the point is that it is handled outside of your code so that you can focus on using your strongly typed dataset the way it was intended. So the way that you should use this, your code above would be rewritten to the following.
In VB.Net:
lCustomerRow = lCustomerTable(0)
In C#:
lCustomerRow = lCustomerTable[0];
Another important thing to note is that CustomerTable implements IEnumberable<CustomerRow>, which means that when you do a foreach loop (or anything with LINQ) you should use the table itself, rather than the Rows property, like so:
foreach (CustomerRow row in lCustomerTable) { DoSomethingWith(row); }
Hopefully this helps resolve anyone's confusion. I haven't used datasets much lately (typed or otherwise) since I started working with LINQtoSQL, which is WAY better at being able to handle data in a strongly typed manner. EntityFramework is probably the same, but I haven't gotten into it yet like I have with L2S. ;)
[EDIT] I think the answer is to actually cast the returned datarow:
lCustomerRow = (CustomerDataSet.CustomerRow)lMyCustomer.Rows[i];
Pity, since i would have thought the Dataset.xsd should contain this casting information.
精彩评论