VB has long been my favorite development language, but, as is typical, even it can definitely be improved in innumerable ways.
One aspect of VB that has always bothered me is string literals. Since VB treats EOL as significant, you can’t have strings that wrap across multiple lines in the environment. This is especially problematic when you deal with SQL queries, report formatting strings, and the like. For instance, this is generally what you see when you have to deal with long SQL queries in VB code.
Dim q as String = "Select *" & vbcrlf q &= "From MyTable" & vbcrlf q &= "Where MyColumn = 1"
Now, you can do a few formatting tricks and clean it up a little, but even then, it’s going to be cumbersome to work with.
One workaround has always been to embed these long, multi-line literals in a Resource file. The VS 2008 IDE even goes so far as to allow you to enter multi-line strings in the resource editor, although you have to use Ctrl-Enter to get a new line:
If you look at the RESX file for the above resource, you’ll see something like this:
All this is certainly workable, and, in many cases, isolating strings to a resource file (of some sort) can be a really good thing, but in other cases, it’s just a pain.
In VB10, Microsoft is finally doing what VB should have done all those years ago. They’re adding “intelligent line continuation” which is to say, you can continue a line in certain syntactic situations simply by continuing the code on a new line. No need for the line continuation underscore char, etc. It won’t necessarily work everywhere (esp in places where it the code would end up ambiguous), but hey, that only makes sense.
In the meantime, you can actually have multi-line string literals in VB.Net without too much pain.
The trick is to use XML Literals. Generally, I’m no fan of XML literals. Once they get peppered with variable references, embedded For loops and other code, they become just so much spaghetti code, albeit with a modern twist.
But, they can be handy for multi-line string literals.
Dim q as String = <String>Select * From MyTable Where MyColumn = 1 </String>.value
So what’s going on here? First, I dim the result variable Q as a string (technically, this isn’t necessary as VB can infer the type, but you get the picture).
Then, I declare the XML Literal with the <String></String> tags. Everything between those tags (even across lines), gets treated as part of the string, no quotes or line continuation needed.
Finally, since the result of the <String></String> tags is going to be an XElement object, and what I want is a string, I need to invoke the value property of the XElement object to retrieve its string value.
And there you go.
But, as with anything good, there are a few caveats.
- line breaks AND whitespace are preserved in the string, which means if you indent those lines, you’ll get space characters where you might not have wanted them.
- if you want to include certain characters that are illegal in XML (for instance, the “<” or “>” characters), you’ll need to escape them.
Handling Escape Characters
One option you have for handling escape characters is to use the XML escape sequences, as in:
Dim q as String = <String>Select * as My>Test<var From MyTable Where MyColumn = 1 </String>.value
The > and < will be replaced with > and < respectively. You can escape any arbitrary character with &#nnn; where nnn is the ascii code of the character.
But this is code, dammit, not XML, and, at least for me, I’d much rather see normal C-style escape sequences (\r\n anyone <g> ) here than have to muck with XML “&” sequences. If we’re talking about web pages and HTML, that might be a different story, though.
At any rate, you can have your cake and eat it too, as it turns out.
Just feed that string through System.Text.RegularExpressions.Regex.Unescape to convert those sequences, hence:
Dim q as String = System.Text.RegularExpressions.Regex.Unescape(<String>Select * as MyTestvar \r\n From MyTable Where MyColumn = 1 </String>.value)
Notice how the XElement.value is simply passed through to the Unescape method to process that \r\n into a normal carriage return/linefeed pair.
Using that, you can now easily embed C-style escaped multi-line strings in your VB code.
But wait, that Unescape call is fairly nasty to look at and use. Wouldn’t it be nice if that was more or less automatic? Well, with a nice Extension Method, it can be.
<System.Runtime.CompilerServices.Extension()> _ Public Function UnEscaped(ByVal v As XElement) As String Return System.Text.RegularExpressions.Regex.Unescape(v.Value) End Function ..... Dim q as String = <String>Select * as MyTestvar \r\n From MyTable Where MyColumn = 1 </String>.Unescaped
First, define an Extension Method that would apply to the XElement object. This is a very simple method that just takes the associated XElement object, retrieves it’s value, and runs that string through the Regex Unescape method.
Since the extension method extends the XElement itself, you can now simply call the Unescaped method directly on the long string definition (the very last line in the code above).
You can’t get much cleaner than that. Or can you? Let me know!