A piece of code today broke that didn't make sense at first. It was so ridiculous that I had to post about it. This isn't a C# is better than VB.NET entry. It's a legitimate "I thought I was supposed to be able to accomplish the same thing in VB.NET as I can in C# and vice-versa" entry. No flame-wars here!
The code was similar to this:
<%# IIf(IsDBNull(Eval("foo")), String.Empty, Eval("foo")) %>
This is something that I do all the time in my C# UI. The C# conditional syntax lends itself nicely to this sort of deal.
<%# Eval("foo") == null ? String.Empty : Eval("foo") %>
I used to get code where developers would literally have a
Label in the
ItemTemplate and on
ItemDataBound cast the
T, analyze the value of a certain property or properties, and set the property of the
Label, etc... accordingly. Not cool with me. I opt for one-lining it whenever humanly possibly; which is what I tried to do earlier today. Only thing is, today I failed miserably.
I knew the code was broken because everything up until this column rendered as it should have. From this column-on everthing stopped. The results set consisted of at least 30 rows. Sweet. Since the code was in my presentation layer I couldn't really breakpoint it so I moved it to my code-behind. I found that there was a
NullReferenceException. Really? I resorted to a different method of accomplishing this task via .aspx page.
<%#IIf(String.IsNullOrEmpty(Eval("foo").ToString), "A", Eval("foo"))%>
Wow. This failed miserably. Let's try something else.
<%#IIf(Eval("foo").ToString.Length = 0, "A", Eval("foo"))%>
This worked... NOT! In case you're curious, I resorted to using "A", "B", "C" for the 3 columns so I know which conditional broke. The first one broke every time.
I know that some of you are thinking that this problem shouldn't even filter down to the UI. By this I mean others have suggested that I take care of this problem in SQL. I already tried this using
COALESCE and then with
ISNULL(FooColumn, '') AS FooColumn
There's a problem with this. What if FooColumn is of type money or integer? The example above wouldn't work (I tried) when the column is of type money or some type of numeric. AFAIK, there is no way to return an empty money value aside from 0.00 (if there is PLEASE let me know!). One of the requirements for this project was that NULL are valid for fields and nothing else should be displayed. That means the following wouldn't work.
ISNULL(FooColumn, 0) AS FooColumn
This would be misleading when the data is displayed because when the customer looked at the data they would think that FooColumn's value was actually 0 when in fact the zero is nothing more than an arbitrary value.
Another "fix" would be to just call
ToString in the
false part of my
IIf statement. That works, to an extent. As soon as you introduce string formatting it won't work as it should.
I could, if I was absolutely desperate; enumerate the rows in the DataSet, check each column for NULL and replace with an empty string. Although it is a very nasty suggestion it would work.
Time for another test scenario. I created 2 console apps: 1 VB, 1 C#. Each does nothing more than declare an
object that happens to be
null as well as a
SqlParameter that sets the value depending on the null'ity of said
First with the VB.
Dim foo As Object = Nothing
Dim parameter As SqlParameter = New SqlParameter()
parameter.ParameterName = "foo"
parameter.Value = IIf(foo Is Nothing, "NULL", "NOT NULL")
Console.WriteLine(IIf(foo Is Nothing, "NULL", foo.ToString))Console.WriteLine(parameter.Value)
object foo = null;
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "foo";
parameter.Value = foo == null ? "NULL" : "NOT NULL";
Console.WriteLine(foo == null ? "NULL" : foo.ToString());
I usually have the parameter name and value taken care of in the constructor as I am a self-confessed one-liner but opted for a more blog-friendly version (i.e. no text-wrapping). Anyway, the results surprised me. Surprised in a "are you f**king kidding me?" and not "This is f**king awesome!" way. To prove that there is no bias, I created the C# version first and used Reflector to disassemble and pasted the VB.NET version into my VB.NET console app.
I ran the C# version first to make sure I wasn't getting frustrated over nothing. As expected the console output was 2 NULL's. Now time for the VB version; unhandled exception (NullReference) at line 12. Line 12 is this gem right here:
Console.WriteLine(IIf(foo Is Nothing, "NULL", foo.ToString))
Hmmm. WTF would I get an exception when I am checking for NULL? Why is
foo.ToString even being interpreted? In other words, how can
foo NOT be
null? At least that's how I looked at this.
After doing a little bit of research I have found that the IIf function will actually analyze the true and the false part of the expression. In other words, it doesn't behave anything like a conditional in C# and is merely a throwback to the VB language.
Further reading of WHY this doesn't work resulted in the fact that if IIf functioned like a C# conditional then code that was ported from VB to VB.NET would break. This is an example of how an explanation can make sense and at the same time not make any sense at all. On the one hand I can see the possible need to make code portable. On the otherhand why would you switch to VB.NET if you expect to write classic VB code? I thought the purpose of going .NET was to embrace the .NET framework, not rely on backwards compatibility.
Again I'll pose the question: Is there a way to accomplish what I am trying to do without abstracting out the functionality to a helper method consisting of a full-blown
IF THEN ELSE statement? Is there a way to one-line this functionality?
As it stands now I have created a
RetrieveFooValue function that takes my object, interprets, and returns an appropriate value. This is the best I could come up with. Again, if there's a more efficient way to do this PLEASE let me know.
<%# RetrieveFooValue(Eval("foo")) %>
RetrieveFooValue contains a full-blown
IF THEN ELSE statment.
I almost forgot how to login to this damn thing! Anyway, good to be back. As you have probably gathered I have been extremely busy. Busy doesn't even do justice to how busy I've been lately. Anyway, I have been working on a large project for the past couple of weeks that just so happens to be developed in..... VB.NET! It's been interesting. Soooo interesting in fact that I decided to make a post about it. Here's a quick snippet.
Dim foo As Nullable(Of Decimal) = IIf(String.IsNullOrEmpty(textFoo.Text), CType(Nothing, Nullable(Of Decimal)), Convert.ToDecimal(textFoo.Text))
If there is no text in the textbox I want a null value; else cast the value to decimal. Easy right? The stored procedure allows for the updating of certain fields as NULL. No big deal.
Response.Write(IIf(foo.HasValue, foo.Value, "NOTHING"))
If there is a value, write it. If not, write something else. Easy right? This actually works. Keeping with the logic of this example take a function that accepts a
Nullable(Of Decimal) parameter. This should be a no-brainer...
parameters.Add(command, "@foo", IIf(foo.HasValue, foo.Value, CType(Nothing, Nullable(Of Decimal)))
Do you think that works? It doesn't. Hopefully I am missing something completely stupid here. The exception I am getting is:
Nullable object must have value.
Let's discuss this. As you can see the expression in my conditional actually checks to see if I have a value. If I do have a value, I want to set my parameter to this value. If I don't have a value, my parameter's value is set to NULL. This is elementary.
Why is it that I am receiving an "object must have value" error when I am checking first for a value? Does that make sense to anyone else? You want to know what works?
If foo.HasValue Then
parameters.Add(command, "@foo", foo.Value)
parameters.Add(command, "@foo", Nothing)
Insert Gob Bluth's "Come On!" here. One of the reasons I love C# so much is because I find that I don't have to write code like this. I really like the idea of writing succinct code (i.e. precise, accomplishing a lot with as few words as possible, one-lining it, etc...). I think even VB.NET developers have to agree that the C# language lends itself beautifully to this type of coding. Other examples include Generics, NullableTypes (decimal?), ??, a ? b : c, stacking using constructs & switch cases, optional curly braces on if statements / using constructs / for / while loops, etc, etc).
The code above that "works" doesn't really work for me. I know that this is personal preference. I have said time and time again how I miss regions when coding VB.NET. This is another prime example of why. Imagine having 6 parameters that are nullable. Instead of region'ing out this wordy code, I have to scroll a screen and a half before I get to my catch block. When I inherit C# code with this coding style the first thing I do is hope for the best. Then I refactor the hell out of it. With ReSharper this is easy as all I have to do is place my cursor to the left of the else and ALT+ENTER the ugliness away (I've gotten Gene Hackman-quick at this).
I digress. Can anyone fluent in VB please help me with conditional statements? I know that the
IIf function is a huge reset and probably looked down upon, but I just can't bring myself to write out a complete
If Then Else. I just can't. C# has spoiled to the point where I can't accept anything less!
I`m not a C# elitist or Visual Basic .NET hater but there are some piss-off points when I end up working on or supporting a VB.NET application. When I first started learning .NET I was writing code in Visual Basic .NET because I came from a Visual Basic background. Over time (especially if I have the choice) I have switched to writing everything in C#. I have even gone so far as to rewrite entire Visual Basic .NET applications or functionality in C#. There are many VB v/s C# debates out there and this isn`t one of them. I`m simply sharing my top 2 beefs (at least with the IDE).
My list of beefs (not all-inclusive) with Visual Basic .NET
- No multi-line commenting in Visual Studio: This is small and nit-picky but to me it`s important.
- No regions within methods: Again, nit-picky but very important to me. I like to think of my screen as real estate, especially when debugging large, complex projects. Adding stored procedure parameters, logging events, error-handling, etc.. can all be "regioned" out. This leaves more important code visible on the screen. I am also a big fan of regioning out sections of the program that have been tested and are in working order. Maybe it`s just a personal thing, but it`s not fun stepping through a routine that is 500 lines* long (that should have been modularized in the first place!) without regioning huge chunks of it.
Of course I consider myself deft when it comes to VB / C#. It`s good to know both (especially for troubleshooting purposes and supporting apps from years back), but if I had to choose one it would definitely be C#.
* I don`t think I have ever had a routine anywhere near 500 lines. If I can`t explain in a sentence what it does then it gets granularized.
Microsoft has released a large list of task-based C# code snippets for Visual Studio 2005. The list contains snippets of code for working with databases and windows applications to writing mobile device applications and networking programs.
There are also VB .NET samples included in the download.
This code is will let you get a glimpse of a URL rewriting engine. There are those of us that don't have the luxury of being able to host our own sites. If you have any questions or can see any way to make this more efficient please let me know.
The Application_BeginRequest section is an ideal location because like the name specifies, this is the first event in the HTTP pipeline chain of execution. When using a Global.asax file, every ASP.NET request response will first start here.
In this code you will noticed the NameValueCollection called blogConfig. Keep in mind that this code was taken from my own application. I happen to keep the path of entry.aspx in an XML configuration file. This is a very easy change to make. Just comment out the blogConfig declaration and change strEntryPath to equal the location of your entry / employee / product / article / etc... ASPX file.
The Regular Expression in strPattern will return a result for the following URL schemas:
The ID's that are picked up will be 444, 210, and 222.
Sub Application_BeginRequest(ByVal sender as Object, ByVal e as EventArgs)
Dim httpContext As System.Web.HttpContext = httpContext.Current()
Dim currentURL As String
Dim strPattern As String = "000(\d+).aspx"
If Request.QueryString("entryID") > 0 Then
currentURL = "000" & Request.QueryString("entryID") & ".aspx"
currentURL = Request.Path.ToLower()
Dim blogConfig As NameValueCollection
blogConifg = ConfigurationSettings.GetConfig("settings/blogConfig")
Dim strEntryPath As String
If blogConfig("entryPath") = "" Then
Response.Write("Please add blog path to configuration file")
strEntryPath = blogConfig("entryPath").ToString()
Dim objRegEx As Regex
Dim Matches As MatchCollection
Dim pageID As String
objRegEx = New Regex(strPattern, RegexOptions.IgnorePatternWhitespace)
Matches = objRegEx.Matches(currentURL)
If Matches.Count > 0 Then
pageID = Matches(0).Groups(1).ToString()
httpContext.RewritePath(strEntryPath & "?entryID=" & pageID)
All that's left to do now is programmatically create static URL's. What I did was run a replace function on my post title stripping illegal characters away and then concatenating the entryID to the end and add .aspx.
Please feel free to e-mail me or post questions relating to this matter and I will try my best to answer them.