Question Unexpected behavior related to default properties and unfound references

T.C.

Member
Joined
Oct 8, 2010
Messages
12
Programming Experience
Beginner
I'm using VB.NET in Visual Studio 2010. Today I encountered two things which are baffling me. Referring to the code below, can someone explain:

1. Why don't I get a syntax error on the Console... line? I was expecting the error "Class System.Data.DataTable cannot be indexed because it has no default property.", but I'm not getting it. Why?
2. When I right click on "Item" and choose "Find All References", the results say "No references available for this item.". Why? There is clearly one reference.​

-TC


VB.NET:
Module Module1

  Sub Main()

    Dim DataTable1 As New System.Data.DataTable
    DataTable1.Columns.Add(New System.Data.DataColumn)
    DataTable1.Rows.Add("Value1")
    Console.WriteLine(DataTable1(0).Item(0))

  End Sub

End Module
 
Answering 2 first, no there is no reference. You just have a bit of invalid code there that makes no sense to the compiler so how can there be a reference to it?

As for 1, unless you're using a typed DataTable from a typed DataSet, the DataTable itself is not a list. In your case, you need to get the desired DataRow from the Rows collection of the DataTable. In long-hand:
Dim fieldValue As Object = myDataTable.Rows.Item(0).Item(0)
That is getting the first item from the Rows collection, which is a DataRow, and then getting the first item from that, i.e. the value from the first column. Given that Item is a common property in all lists and is the default property, people generally just omit it, so that code becomes:
Dim fieldValue As Object = myDataTable.Rows(0)(0)
Unlike VB, C# has no Item property and you have to index the list directly like that, which is why the C# equivalent of a default property like Item is known as an indexer.
 
Thank you for the assistance. However, I still don't fully understand what is going on. Just to be clear, my code runs with no errors.

1) I see why your code works, but I don't see why my code works. Since there is no default property of a DataTable, shouldn't DataTable1(0) generate a syntax error?

2a) Why do you say "Console.WriteLine(DataTable1(0).Item(0))" is invalid and makes no sense to the compiler? Is it because DataTable1(0) shouldn't compile? If so, that's what I thought too! But it does compile. That's why I'm asking Question 1.

2b) My perception is that "Find All References" simply doesn't work on some indexers. It doesn't work on either Item property in "Dim fieldValue As Object = myDataTable.Rows.Item(0).Item(0)". Yet if I create my own class with a default property, "Find All References" works as expected. Is there some logic behind this, or is Visual Studio just buggy?

-TC
 
Hmmm... I don't think I read your post carefully enough. Sorry about that.

Your code compiles courtesy of the fact that your project has a reference to System.Data.DataSetExtensions by default. If you remove that reference you'll find that the compiler will reject your code as you expect. I'm not 100% sure which but the compiler is adding some extension method calls implicitly. I would assume that there would be a call to AsEnumerable but that still doesn't produce an IList, which is where the Item property comes from. I'm guessing that it adds an ElementAt call too, but I think that you'd have check the IL code after compiling to find out for sure.
 
compiler would translate Dim v = dt(0)(0) to:
Dim v As Object = RuntimeHelpers.GetObjectValue(dt.AsEnumerable().ElementAtOrDefault(Of DataRow)(0).Item(0))
 
I'm not sure why we're having a discussion about trying to break the code but a standalone Datatable has no column type, default or otherwise, and Item is soooooo a member of Datatable (have we got it confused with Items?) In the following Column1 contains both a string and an integer and the compiler doesn't bat an eyelid!

Dim DataTable1 As New System.Data.DataTable
Dim x As Int16 = 9
DataTable1.Columns.Add(New System.Data.DataColumn)
DataTable1.Columns.Add(New System.Data.DataColumn)
DataTable1.Rows.Add("Value1", "Value1a")
DataTable1.Rows.Add("Value2", x)


ListBox1.Items.Add(DataTable1(1).Item(0))
DataTable1(1).Item(1) = DataTable1(1).Item(1) + 3
ListBox1.Items.Add(DataTable1(1).Item(1))
 
Thanks, guys. You've been a big help. I think I get it now: When an object is indexed, the compiler checks to see if the class is either enumerable or has a default property. Ordinarily, the DataTable class is not enumerable, but when extended with System.Data.DataSetExtensions, it is. That's why I don't get an error when I try to index DataTable1. (I've confirmed that I do get the error when I remove the reference to DataSetExtensions.)

This leads me to a new question: How would a programmer know that the extended DataTable is enumerable? I'm searching the object browser and the help files, and I can’t find any confirmation that, for instance, an extended DataTable implements IEnumerable (or something like that).

This is the first time I’ve encountered a class extended in this way, and I must say that I don’t like it. First of all, the behavior of the class depends on which libraries are referenced, and that seems to place an extra burden on the programmer to know what is referenced and what isn’t, and the behavior to expect in each case. Second, the documentation doesn’t seem to be keeping up. Intellisense and the object browser gave me no clue to what was going on; if it wasn’t for you guys, I still wouldn’t know. Given these clear disadvantages to DataSetExtensions, why did Microsoft extend in DataTable this way? Why didn’t they just create an inherited class instead?


Dunfiddlin, to answer your question about why we are discussing this: This issue burned me badly yesterday. I expected the compiler to catch errors which it didn’t catch; instead those errors manifested as runtime errors and improper behavior of the application. I lost several hours cleaning things up. Now I’d like to understand why this happened so I can avoid it in the future.


Also, does anyone have a clue why I can’t find all references to DataRow.Item? It is a real inconvenience to the work I’m doing today.


-TC
 
Extension methods doesn't change existing behaviour of a class, they add behaviour. If you know about and want this added functionality you must add references for it, without the code won't compile.

Most, if not all, .Net (MS) provided extensions were added to support LINQ, as such DataTableExtensions links DataTable to LINQ. Why they did it this way is because they didn't want to change the old base libraries. When they introduced .Net 3.0 and 3.5 these were 'addon' frameworks, everything .Net 2.0 was unchanged (and still for the most part is). Many of these extensions also supports a wide range of types, for example any kind of collection type that implements IEnumerable(Of T) would get the added functionality of IEnumerable(Of T) type extensions.

Further, you can also define your own extension methods, to add functionality for any type that you can't change itself. This adds to the extensible design that were introduced along with partial types.

Why didn’t they just create an inherited class instead?
An inherited class is a different type, which would mean it could not be used in place of the DataTable type. Any code that produced a DataTable would have to change to produce instances of the different type, that code would also need casting or else any involved definitions using the 'previous' type had to be changed also. As mentioned, extensions does not change the existing type, it only adds functionality that can be utilized by the aware consumer.
 
John H,

Thanks for explaining that. I'm sure you're right, but I think it will take some time before I really appreciate the merit of extensions.

In any case, I'm still struggling to understand how, as a programmer, I would know the properties, methods, and interface implementations of an extended class. I'm looking at DataTable in Object Browser right now, and I've checked the box "Show Extension Members", but I still don't see the extended method AsEnumerable listed there. Am I missing something?

-TC
 
I'm still struggling to understand how, as a programmer, I would know the properties, methods, and interface implementations of an extended class. I'm looking at DataTable in Object Browser right now, and I've checked the box "Show Extension Members", but I still don't see the extended method AsEnumerable listed there. Am I missing something?
In Object Browser member list a "Extension Members" folder appears at top. At least it does that in the VB 2010 IDE I'm using:
OBextensions.png

All members, including extensions, are also documented in the member list in help: DataTable Class (System.Data)
 
Item is soooooo a member of Datatable

Um, you what? Item is pretty much universally an implementation of the IList.Item property. DataTable doesn't implement IList, therefore it doesn't implement IList.Item. You try writing myDataTable.Item in code and see how far you get. The code you're using, e.g. DataTable1(1).Item(1), is referring to the Item property of a DataRow, not a DataTable. As I said before, remove the reference to System.Data.DataSetExtensions.dll and even that code will fail to compile, as it would have in .NET 2.0, when that library didn't exist.
 
In Object Browser member list a "Extension Members" folder appears at top. At least it does that in the VB 2010 IDE I'm using:
View attachment 3355

John,

Thank you for showing me that extension members appear in Object Browser for you.

After seeing that, I experimented with Object Browser some more, and I found that it behaves inconsistently for me. Extension Members appear sometimes, but not other times. For instance, if I use the "Browse:" combo box to look at "My Solution", Extension Members do not appear for DataTable; but if I look at ".NET Framework 4", they do appear; and if I look at "All Components" they appear for DataTable 2.0.0.0, but not for DataTable 4.0.0.0. In any case, when I navigate to Object Browser by choosing "Go To Definition" from my code, Extension Members never appear. (I'm using Visual Studio 10.0.40219.1 SP1Rel and my code is targeting .NET Framework 4.)

If there is some logic to this behavior of Object Browser, I'm curious to know what it is. However, at this point, I'm satisfied that I've pursued this issue far enough. It is comforting to know that Microsoft intended for extended members to appear in Object Browser (even if they don't) because it confirms that I'm thinking about extensions in the right way; whereas when I thought extension members were untrackable little gremlins, it made me feel like I just didn't get what was going on.

Thanks.
-TC
 
Back
Top