‘Stupid’ Question 20: How should I do casting in C#? Should I use the prefix cast or the as-cast?
I remember when we learned about casting in school. It was when we learned about the hashtable. My teacher took the trash bin and walked around and put things it (even grabbing a few personal items from the students,- just for laughs). As some of the students on the front row got to fish out some of the items from the bin giggling he explained casting to us.
Casting in C# - how should I do this magic?
We learned to use the classic cast, we learned both ways, but the prefix cast stuck better with me in the beginning. I don’t know when, but at some point I started noticing ‘as’ casting in code examples and immediately liked the syntax better- it was more readable, even if I was skeptic to the lack of parentheses that I had learned to love. So I have to admit, I started using it without really looking into what it meant. I just assumed it was the same. But then I started getting weird exceptions. I was getting the dreaded NullReferenceException from my methods. What do you mean null??
So I asked myself, what is the difference between these two types of casting, and when should I use them?
The classic cast or prefix cast throws an InvalidCastException if the cast is not valid and should be used when you are expecting the cast to succeed - which seems to be the main recommendation (the question being why would you expect the casting to fail?- and is this (‘as’) the best way to handle that?)
With the ‘as’ casting a null will be returned if the conversion fails,- so this means that you can ‘test’ a cast – but also that the type has to be nullable or be able to take a null. This cast should be used when you are not sure if the casting will succeed.
Like somebody put it on stackoverflow:
Use as when it’s valid for an object not to be of the type that you want, and you want to act differently if it is.
And to quote the famous Lippert:
I think I covered that in the article, but to sum up, here are two ways to think about it.
First, “as” means “I expect that sometimes this will not succeed, give me null in those cases”. A cast means “I expect that this will always succeed; if I am wrong, then please crash the program”.
Second, “as” means “I want to know what this object *really is*, not what it is convertible to by some representation-changing specially-defined conversion rule. A cast means “convert this thing using whatever crazy mechanism you need to do to make it work.”
Choose the one that matches the meaning you intend to implement. – Eric
Comments
You asked a follow-up question to Julie Lerman on Twitter. The question was, "I have a new question in RE to Q20- is the performance win with 'as' something that matters today?" I hope you don't mind me answering. The answer in most cases is no. An explicit cast (you call prefix cast) compiles down to the castclass IL operation. And a fast cast (as-cast) compiles down to the isinst IL operation. The isinst operation is slightly faster. The fast cast becomes the most performant when you're doing a lot of casts or there is a high likelihood of casting exceptions -- for example at a public interface where you cannot be certain of the type of a passed argument. I generally base my decision on my expectations of my code. Do I expect that received arguments are likely to be of an unexpected type? If so, I use the fast cast. But, if I have a reasonable expectation that my received argument is going to be castable then I'll use an explicit cast and provide exception handling. Explicit casting is probably a good candidate if your code looks something like this: void Foo(object a1) { BaseObj b = a1 as BaseObj; if (b != null) { // do something; omitted for brevity } else { throw new Exception("..."); // or even // Trace.TraceError("..."); } } You can achieve the same thing with this: void Foo(object a1) { try { BaseObj b = (BaseObj)a1; // do something; omitted for brevity } catch (InvalidCastException) { // note: no exception object throw new Exception("..."); // or even // Trace.TraceError("..."); } }
Keep in mind that the 'is' syntax only works with reference or nullable types, so sometimes you're just stuck with (cast)primitive.
Great question. I followed up at http://msmvps.com/blogs/kathleen/archive/2012/08/12/to-as-or-not-to-as.aspx
I would say there is more to it than just the conversion. While the idea of conversion can fail sometimes is valid, I have rarely seen code that uses "as" to really mean that. Cast conversions is almost always used when we expect things to succeed. Using a direct cast can throw an exception and we know exception raising is a heavier operation since it unwinds the stack and takes the execution to one upper level. Checking for if (null) would be easier and will let the program flow more smoothly from that point on. So apart from the intended meaning, i would give more weightage of if i am willing to get exception or not.
Nice post! Perhaps adding a paragraph about Convert.ToXXX() and comparing that to "as" and direct casting would be great too.
There's an old saying which goes "Expect the best, but plan for the worst". Specifically here, One should always expect that a cast will work, but plan for it to fail. And, since I"M going to handle what to do in case of the cast failing, I always do a "as" cast, since I am ALWAYS going to test for null immediately afterwards. (And, since about 95% of the time, a null value is equally bad as a non-null value of the wrong time, you can handle both checks with one if(). ) The one place where I do use explicit cases (which everyone here sort-of hints at without coming out and saying) is when trying to un-box a value type. That can only be done with an explicit case.
Last modified on 2012-08-11