C# "as" cast vs classic cast [duplicate]

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.


Solution 1:

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:

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:

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:

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:

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.