I Love It When Logic Comes Together
I just proved to myself something. It's interesting, sure, but mostly I'm just pleased that I'm right :)
On Friday, a co-worker asked me if he needed to wrap the VB TypeOf keyword around a null check. While I try to appear godlike at work and seem to have all the answers, I really couldn't come straight out with the answer.
The easy way to find out is to check either a) the doco, or b) run it with a null and see if it goes kaboom. I chose neither. Times like these allow me to increase my IL knowledge just that little bit more, so I wrote a quick piece of code so that I could view the IL in reflector.
Private Class TestTypeOf
End Class
Private Sub DoTypeOfCheck()
Dim foo As TestTypeOf = Nothing
If TypeOf foo Is TestTypeOf Then
Debug.WriteLine("true")
Else
Debug.WriteLine("false")
End If
End Sub
Having done this, it's time to jump to reflector and have a look at the IL.
So, now we can see that the TypeOf keyword in VB is simply a wrapper around the IL call isinst, and the result of the call is tested for null. Now it was time to look up isinst in my trusty copy of The Common Language Infrastructure Annotated Standard.
The book told me what it does, and what exceptions are thrown, but it didn't come right out and tell me if it threw an exception if you passed it null. I should have logic-ed it out that it wouldn't, but maybe I was just itching to watch it blow. I ran my code and discovered that it doesn't blow up, just returns false in this case.
But the book also mentioned that it's very similar to the castclass call. The main difference is that isinst will only throw a TypeLoadException if it can't find a definition of the class you're interested in, whereas castclass will also throw an InvalidCastException if the instance can't be cast. When calling isinst, an actual cast takes place, just like for castclass - the difference is that it won't throw an exception, only return null. But they both do the actual cast.
This was fine and dandy, and my coworker went back to work, deleting the lines of code that he'd just written :)
Today I was thinking about it even more. I'd been pushed onto another train of IL playing and looking as a result of reading Joel Pobar's newest blog entry, CLR Dynamic Languages under the hood (Part 1 of many) - go read this by the way, it's very cool.
It occurred to me while I was playing with IL again that it's a shame that VB didn't wrapper the isinst call. This sounds like a nice way of having some conversions done, and it also seems like a waste that if we have code like this:
If TypeOf foo Is TestTypeOf Then
foo2 = DirectCast(foo, TestTypeOf)
End If
Then we really have two casts being carried out - once for the TypeOf, once for the DirectCast (and we really do - compile and look at the IL, it really happens - there's an isinst and a castclass call :) Surely it would be quicker to only cast once and then check for null, than cast twice?
Then it struck me. In VB in the 2.0 framework there's a new keyword - TryCast. TryCast will do a cast if possible, otherwise return null - and there'll be no exception. Of course, I had to prove the theory.
I wrote the following in VS2005B2:
Private Class Class1
End Class
Private Sub SomeFunc(ByVal sender As System.Object)
Dim i As Class1
i = TryCast(sender, Class1)
i = DirectCast(sender, Class1)
End Sub
Then we check the IL, and I see that I'm right *muhahaha*. TryCast calls isinst, and DirectCast calls castclass.
I love being right. It's educational for all of us :)