50

If there is a difference, what is the difference between the two ways of doing the following cast?

In this case e is a GridViewRowEventArgs object.

GridView gv = (GridView)e.Row.FindControl("gv"); //first way

GridView gv2 = e.Row.FindControl("gv") as GridView; //second way
vauhochzett
  • 2,732
  • 2
  • 17
  • 40
Xaisoft
  • 45,655
  • 87
  • 279
  • 432

8 Answers8

84

The differences are:

  • If a cast fails, it throws an InvalidCastException.
  • If the as operator fails, it just returns a null reference.
  • You can't use as with non-nullable value types (e.g. you can't do "o as int").
  • The cast operator is also used for unboxing. (as can be used to unbox to a nullable value type.)
  • The cast operator can also perform user-defined conversions.

EDIT: I've written elsewhere about when I feel it's appropriate to use which operator. That might be worth a read...

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • There's not much need - I've explained more in my answer now :) – Jon Skeet Mar 31 '09 at 17:54
  • Great thanks, I actually did updated it with a GridView, but your answer is good enough. – Xaisoft Mar 31 '09 at 17:57
  • A couple questions, is the as operator an actual cast? Is one faster than the other? – Xaisoft Mar 31 '09 at 17:58
  • I would suggest changing the question back to a non-nullable type because now the answer is confusing when first read. – Paul Ruane Mar 31 '09 at 18:01
  • @Paul: I'll fix the answer instead. @Xaisoft: They're basically about as fast as each other. – Jon Skeet Mar 31 '09 at 18:03
  • Another significant difference - the as operator is significantly faster than the cast operator. – Not Sure Mar 31 '09 at 18:04
  • I'm going to include a link since it appears I'm calling out Jon Skeet, and that's dangerous. http://stackoverflow.com/questions/57701/what-are-the-performance-characteristics-of-is-reflection-in-c – Not Sure Mar 31 '09 at 18:06
  • 1
    @Not Sure: I dispute that. Please provide evidence. Note that using an "as" and a null check *is* faster than doing "is" and then a cast, but that's not the same thing as saying that "as" is faster than the cast. – Jon Skeet Mar 31 '09 at 18:07
  • @Not Sure: Doing a cast is slower *if it throws an exception* certainly, but in the success case they're basically the same. Also note that the linked answer says exactly what I do about "is + cast" is slower than "as + null check". It doesn't say which is faster in the "just as/cast" success case. – Jon Skeet Mar 31 '09 at 18:31
  • @Jon Skeet: The cost of looking for the user conversion you mention above is non-zero, which only the prefix cast does, and is a "success". I agree that in the trivial case of the instance already being of the cast type, they should perform the same, but that's just one use case. – Not Sure Mar 31 '09 at 19:40
  • @Not Sure: No, the cost of looking for the user conversion is done at compile-time. – Jon Skeet Mar 31 '09 at 19:44
  • And I wasn't talking about the trivial case of the instance being of the actual cast type - I'm talking about any "success" scenario. Given that the results of the failure scenario are so radically different (throwing an exception or not) I don't think it's sensible to compare the performance there. – Jon Skeet Mar 31 '09 at 19:45
  • Going back to the user-defined conversion: if the C# compiler emits a "castclass" instruction instead of calling op_Explicit or op_Implicit, the cast *will fail*. I have a test application which demonstrates this if you want to see it. – Jon Skeet Mar 31 '09 at 19:49
  • @Jon Skeet - I disagree, it's quite sensible to compare performance of these different casting methods since either can be and are commonly used for the same purpose of a runtime type check. – Not Sure Mar 31 '09 at 20:06
  • @Jon Skeet - By the way, you appear to contradict yourself here: http://blogs.msdn.com/csharpfaq/archive/2004/03/12/88420.aspx. "The as operator appears to be slightly faster in v1.0 and v1.1 of Microsoft's CLR compared to casting," unless something has changed in later CLR versions. – Not Sure Mar 31 '09 at 20:10
  • @Not Sure: I'm pretty sure it *has* changed. Either way, it certainly isn't "significantly faster" as per your original claim. We could benchmark it if you want. – Jon Skeet Mar 31 '09 at 20:13
  • @Not Sure: If the aim is just to do an execution time check, you certainly shouldn't be casting and then presumably catching the exception. That would be crazy. If you *just* want a check, use "is". If you want a check and then use the value of the new type, use "as" and then a null check. – Jon Skeet Mar 31 '09 at 20:14
  • If you want to use the new type and you *want* an exception if it's the wrong type (because that indicates a bug in some code for your situation), use a cast. It seems pretty simple to me. – Jon Skeet Mar 31 '09 at 20:14
  • @Jon Skeet: The argument isn't about the appropriateness of which use case, it's about the performance difference under the specific use case, which is common practice regardless of whether you and me know better. – Not Sure Mar 31 '09 at 20:36
  • It *only* makes sense to compare performance when the results are the same. I don't think when Xaisoft asked about which was faster he was asking about the *failure* case. It's blatantly obvious that an exception is slower than returning null. – Jon Skeet Mar 31 '09 at 20:50
  • So, are you claiming that when both cast and "as" succeed (i.e. return a non-null reference) that "as" is *significantly* faster? – Jon Skeet Mar 31 '09 at 20:51
  • The use of the adjective significantly in my original post was in error, but as is still faster than prefix. The difference in CLR 1.0/1.1 was slight in your words. My test with 3.5 shows the difference to still exist, but is very negligible. Googling "C# casting performance" confirms this. – Not Sure Mar 31 '09 at 21:32
  • Okay, I'm content with that. I certainly wouldn't have disputed "it's faster but only a tiny bit" or something like that. "Significantly" gives the wrong impression. I'm relieved to see I allowed myself some leeway originally by saying they're "about" as fast as each other :) – Jon Skeet Mar 31 '09 at 21:45
9

What isn't mentioned in the above answers is intent -- why are you performing the conversion, and (more importantly) what happens on the lines after the conversion?

For example, I've seen code similar to the following a number of times:

if ((foo as SomeType).SomeMethod()) { /* ... */ }

This could be compared to the cast-using version:

if (((SomeType) foo).SomeMethod()) { /* ... */ }

So, which of these is better?

The cast is.

Using as will result in a NullReferenceException if the conversion fails.

Using a cast will result in an InvalidCastException if the conversion fails.

Now tell me, which is a more useful exception for debugging? A NullReferenceException, which could be produced by nearly anything, or an InvalidCastException, which lets you know what actually went wrong?

Thus, only use as if the conversion is actually optional (meaning that there must be a null check before using the variable). Otherwise, use a cast, thus making your intentions more explicit.

jonp
  • 13,512
  • 5
  • 45
  • 60
4

The safe cast as

variable as type

does the same as

(variable is type) ? (type)variable : (type)null

and will not work for value types.

Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143
2

In general, the difference between a static cast and "as", is that the cast will throw an Exception if it fails, whereas "as" will just set the variable to null.

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
2

The "as" statement basically makes an attempt to cast the variable, and returns null if it fails rather than throwing an exception. As such, the value to which you're casting must be nullable - a reference type or a nullable primitive. In your example, you'd have to do:

int? i2 = o as int;

or it won't compile.

Jerod Venema
  • 44,124
  • 5
  • 66
  • 109
1

If you however used a reference type say Table the first one would raise InvalidCastException in case o was not assignable to Table and the second would just return null.

Rashack
  • 4,667
  • 2
  • 26
  • 35
1

Apart from the issue which Jon pointed out, the as keyword effectively casts o as SomeClass. If o isn't derived from SomeClass it returns null. Whereas a simple cast would throw an exception.

SomeClass i2 = o as SomeClass;

becomes

SomeClass i2;
if (o is SomeClass)
    i2 = (SomeClass)o;
else
    i2 = null;
Ken Browning
  • 28,693
  • 6
  • 56
  • 68
0

I might be stating the obvious here, but one thing that you get with the 'as' cast is, that you are guaranteed to end up with an object of the type you requested. This comes in handy in certain situations.

Jakob
  • 1