Thursday, January 12, 2006

How does VS.Net's Call Stack window infer the language the assembly was written in?

From the .pdb file it seems, sadly. Take that away, and it blanks out.

So I still don't know of any reliable way of determining what language an assembly was written in purely from the assembly / manifest. Of course it shouldn't matter - but it's nice to know...

VB.Net vs C#

(As if the debate hadn't been done to death already, right?)

I'm not a big fan of VB. Frankly the syntax sends beads of sweat down the small of my back, and attempting to find the right method using those pull-down thingies gives me fits. However even I'd have to admit, there's no real 'big ticket' items that you could wave about to say 'VB is shit' (or 'C# is shit' if you're that way inclined).

Instead what we're into here is market differentiation. This is normally known as price descrimination, but in this case it's more like developer differentiation (note how I avoided saying something like 'intelligence descrimination' ;-). Because ultimately we're advocating the same thing - .Net - and buying another house for BillG with our licences.

Whilst we sit divided, bickering over the relative merits of curly braces vs End Sub, what we should be discussing is the more important issues like:
  • when Microsoft will properly support test-driven development in it's toolset?
  • whether J2EE has caught up / overtaken .Net yet (how come all the good stuff - think log4net, NMock, NHybernate etc... is all java ports)?
  • is there yet a sensible framework for developing on Linux?
It's like a debate over white vs black iPods. Us .Net developers really need to get out more...

Monday, January 09, 2006

How to abort VS solution build when project build fails

On bigger projects one of the most irritating bits about Visual Studio .Net is it's 'carry on regardless' approach to multiple project compilation. A project fails, so instead of halting so you can fix it, you get a zillion build errors in all the other projects that reference it. This just slows down the build-fix cycle, not least because the 'root cause' error is drowned out in noise (the Task List window is useless in this regard, one has to find the first instance of the word 'Error' in the build output, and work from there).

There's a simple macro fix for this, terminate the build after the first error, however every time I move machine I forget where to find it (it strangely eludes my google-fu). So here it is:

Private Sub BuildEvents_OnBuildProjConfigDone( _
ByVal Project As String, _
ByVal ProjectConfig As String, _
ByVal Platform As String, _
ByVal SolutionConfig As String, _
ByVal Success As Boolean) Handles _

If Success = False Then
DTE.ExecuteCommand("Build.Cancel", "")
Dim win As Window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
Dim OW As OutputWindow = CType(win.Object, OutputWindow)
OW.OutputWindowPanes.Item( _
"Build").OutputString( _
"ERROR IN " & Project & _
" Build Stopped" & _
End If
End Sub
Why this isn't in the IDE from the get go amazes me. Did no-one at Microsoft ever write a multi-project solution in VS.Net?

Incidentally why is there no upward limit on the errors reported even within a project? One project I worked on had one massive code-gen'd file. When this broke, there could be upwards of 10,000's of build errors generated, which totally locked up the IDE for 5 minutes at a time. It wasn't responsive enough to manually Cancel Build, so you'd have to sit it out. I emailed the VS team lead (literally years ago) and his response was something like 'what a good idea'. So where's the fix?

Homily #1: Late binding is for code-gen only

Today's message: don't use late binding in any code that you (rather than the machine) wrote.

Why would you? No intellisense, no compiler safety net, diminished performance (in some cases). Even when you're sure you've got the right member, did you spell it right (and did you get the casing right, where applicable)?

It's not like it's hard to do either, eg:
  • Generate a strongly-typed dataset, and load the data into that instead, or
  • Use one of any number of code-gen tools to build objects from your data
  • For 'magic values' held in a database (or otherwise), use code-gen to import them into your code as constants / enumerations, and use them from there
It's the OnceAndOnlyOnce principal again: any time you build a 'wrapper' object like this you're centralizing the knowlege and maintanance of the binding contract in one place, and whilst you're not isolating the application from it (typically you'd expose members with names matching the data columns), any breakages are caught by the compiler.

Popular Posts