C# "as" cast vs classic cast

C#Casting

C# Problem Overview


> Possible Duplicate:
> Casting vs using the ‘as’ keyword in the CLR

I recently learned about a different way to cast. Rather than using

SomeClass someObject = (SomeClass) obj;

one can use this syntax:

SomeClass someObject = obj as SomeClass;

which seems to return null if obj isn't a SomeClass, rather than throwing a class cast exception.

I see that this can lead to a NullReferenceException if the cast failed and I try to access the someObject variable. So I'm wondering what's the rationale behind this method? Why should one use this way of casting rather than the (old) one - it only seems to move the problem of a failed cast "deeper" into the code.

C# Solutions


Solution 1 - C#

With the "classic" method, if the cast fails, an InvalidCastException is thrown. With the as method, it results in null, which can be checked for, and avoid an exception being thrown.

Also, you can only use as with reference types, so if you are typecasting to a value type, you must still use the "classic" method.

Note:

The as method can only be used for types that can be assigned a null value. That use to only mean reference types, but when .NET 2.0 came out, it introduced the concept of a nullable value type. Since these types can be assigned a null value, they are valid to use with the as operator.

Solution 2 - C#

Null comparison is MUCH faster than throwing and catching exception. Exceptions have significant overhead - stack trace must be assembled etc.

Exceptions should represent an unexpected state, which often doesn't represent the situation (which is when as works better).

Solution 3 - C#

In some cases, it's easily to deal with a null than an exception. In particular, the coalescing operator is handy:

SomeClass someObject = (obj as SomeClass) ?? new SomeClass();

It also simplifies code where you are (not using polymorphism, and) branching based on the type of an object:

ClassA a;
ClassB b;
if ((a = obj as ClassA) != null)
{
    // use a
}
else if ((b = obj as ClassB) != null)
{
    // use b
}

As specified on the MSDN page, the as operator is equivalent to:

expression is type ? (type)expression : (type)null

which avoids the exception completely in favour of a faster type test, but also limits its use to types that support null (reference types and Nullable<T>).

Solution 4 - C#

The as operator is useful in a couple of circumstances.

  1. When you only need to know an object is of a specific type but don't need to specifically act on members of that type
  2. When you'd like to avoid exceptions and instead explicitly deal with null
  3. You want to know if there is a CLR conversion between the objects and not just some user defined conversion.

The 3rd point is subtle but important. There is not a 1-1 mapping between which casts will succeed with the cast operator and those which will succeed with the as operator. The as operator is strictly limited to CLR conversions and will not consider user defined conversions (the cast operator will).

Specifically the as operator only allows for the following (from section 7.9.11 of the C# lang spec)

  • An identity (§6.1.1), implicit reference (§6.1.6), boxing (§6.1.7), explicit reference (§6.2.4), or unboxing (§6.2.5) conversion exists from the type of E to T.
  • The type of E or T is an open type.
  • E is the null literal.

Solution 5 - C#

The as keyword is useful when you genuinely don't know what type the variable might be. If you have a single function that will follow different code paths depending upon the actual type of the parameter, then you have two choices:

First, using a normal cast:

if(myObj is string)
{
    string value = (string)myObj;

    ... do something
}
else if(myObj is MyClass)
{
    MyClass = (MyClass)myObj;
}

This requires that you check the type of the object using is so that you don't try to cast it to something that will fail. This is also slightly redundant, as the is-type checking is done again in the cast (so that it can throw the exception if required).

The alternative is to use as.

string myString = myObj as string;
MyClass myClass = myObj as MyClass;

if(myString != null)
{

}
else if(myClass != null)
{

}

This makes the code somewhat shorter and also eliminates the redundant type checking.

Solution 6 - C#

I think the best 'rule' would be to only use the 'as' keyword when it's expected that your subject won't be the object you're casting to:

var x = GiveMeSomething();

var subject = x as String;

if(subject != null)
{
  // do what you want with a string
}
else
{
  // do what you want with NOT a string
}

However, when your subject SHOULD be of the type you're casting to, use a 'classic cast', as you call it. Because if it isn't the type you're expecting, you'll get an exception which fits the exceptional situation.

Solution 7 - C#

using as will return null if not a valid cast which allows you to do other things besides wrapping the cast in a try/catch. I hate classic cast. I always use as cast if i'm not sure. Plus, exceptions are expensive. Null checks are not.

Solution 8 - C#

There's nothing deep happening here.. Basically, it's handy to test something to see if it's of a certain type (i.e. use 'as'). You would want to check the result of the 'as' call to see if the result is null.

When you expect a cast to work and you want the exception to be thrown, use the 'classic' method.

Solution 9 - C#

You use the "as" statement to avoid the possibility of an exception, e.g. you can handle the cast failure gracefully via logic. Only use the cast when you are sure that the object is of the desired type. I almost always use the "as" and then check for null.

Solution 10 - C#

I suppose it is useful if the result of the cast will be passed to a method that you know will handle null references without throwing and ArgumentNullException or suchlike.

I tend to find very little use for as, since:

obj as T

Is slower than:

if (obj is T)
    ...(T)obj...

The use of as is very much an edge-case scenario for me, so I can't think of any general rules for when I would use it over just casting and handling the (more informative) casting exception further up the stack.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChrisView Question on Stackoverflow
Solution 1 - C#Brian BallView Answer on Stackoverflow
Solution 2 - C#Matěj ZábskýView Answer on Stackoverflow
Solution 3 - C#ZoobaView Answer on Stackoverflow
Solution 4 - C#JaredParView Answer on Stackoverflow
Solution 5 - C#Adam RobinsonView Answer on Stackoverflow
Solution 6 - C#Erik van BrakelView Answer on Stackoverflow
Solution 7 - C#Dustin DavisView Answer on Stackoverflow
Solution 8 - C#RQDQView Answer on Stackoverflow
Solution 9 - C#Keith BluestoneView Answer on Stackoverflow
Solution 10 - C#Quick Joe SmithView Answer on Stackoverflow