I ran across a painful problem late last week with DataTables in VB.NET. It started when I realised that my derived class off a DataTable wasn’t serializing the instance members specific to that derived class. I dug around and discovered that things get worse. Not only have others discovered my pain, but under VB.NET I’m not allowed to step in and supply alternative serialization code for the subtype myself. The proposed solution? Work around the issue with your own serialization code in C#, then put a VB.NET wrapper around the workaround to get access to it. Though our reasons differ slightly, my supervisor and I agree that throwing a microscopic piece of C# into an entirely VB.NET application just isn’t going to happen.
Yet again, I am underwhelmed by the “second-class-citizen” approach Microsoft seems to have with respect to VB.NET. First, there was that little fiasco where key basic refactoring tools are offered in the vanilla Visual Studio for C#, but not VB.NET (yes, yes, I’m quite aware of the addons. Why they are necessary for VB.NET but not C# is what’s getting my goat). Secondly, there’s that craziness where reflection doesn’t quite work the same under C# vs VB.NET (oh the fun times on forums peeps had on that one). And now, this… I’m wondering what’s next in the hit-parade of C# > VB.NET shennanigans that I’ll trip over.
It’s a bit of a crying shame really… I cut my teeth on a succession of languages based on C. I’ve been playing in VB.NET long enough now, that I think finally grok “syntactic sugar causes cancer of the semicolon“.
So, what did I do? First I pulled out NUnit and confirmed for myself that I really was dealing with a situation where base DataTable state would serialize, that new derived class members won’t, and that I can’t do my own serialization for the derived class.
I then thought very hard about options. The derived class provides strongly typed properties when accessing rows, and has kept complexity in my recursive reflection parser in the “understandable by humans” zone, so the derived class needs to stay.
Finally, I turned the the new members in the sub-class, and considered their lifecycle. They’re essentially static context that the DataTable needs when when I parse VB.NET structures into the DataTable. Once they’re in the DataTable, they’re basically redundant. I finally sorted out something that I will call “tolerably sh*tty” when the supervisor asks:
Initially, the “context” was being passed into the ParameterTable constructor. This context is the new member state that serialization of DataTable refused to touch.
I’ve decided on an approach where I added an interface that explicitly ties down exactly what constitutes this static context, and have both the ParameterTable and its container class implement it. The interface allows me to ensure that I avoid a circular dependency where the ParameterTable explicitly knows its container, and it forces me to handle the static context in the same way in both classes. In ParameterTable, if it finds it has context supplied externally, that will be used (necessary for the reflection parser). Otherwise, once the table is fully parsed, it can derive the information it needs from its own internal state.
I’m not wedded to this as a final solution, but it works and I hate it less than a VB.NET wrapper around C# code that I should have been able to do all in the one language.