richard
richard

Reputation: 12498

.NET - How is explicit cast with "as" different (internally) from (someType)someobject, and why?

I understand that when you use an explicit cast like this:

(someType)someobject

you can get an invalid cast exception if someobject is not really someType.

As well I understand that when you cast with as like this:

myObject = someObject as someType

myObject is just rendered null if someObject isn't really someType.

How are these evaluated differently and why?

Upvotes: 8

Views: 4060

Answers (2)

Sem Vanmeenen
Sem Vanmeenen

Reputation: 2151

John Skeet has a C# faq where he explains the differences between the two operators. See paragraph 'What's the difference between using cast syntax and the as operator?'.

Quote :

Using the as operator differs from a cast in C# in three important ways:

  1. It returns null when the variable you are trying to convert is not of the requested type or in its inheritance chain, instead of throwing an exception.
  2. It can only be applied to reference type variables converting to reference types.
  3. Using as will not perform user-defined conversions, such as implicit or explicit conversion operators, which casting syntax will do.

There are in fact two completely different operations defined in IL that handle these two keywords (the castclass and isinst instructions) - it's not just "syntactic sugar" written by C# to get this different behavior. The as operator appears to be slightly faster in v1.0 and v1.1 of Microsoft's CLR compared to casting (even in cases where there are no invalid casts which would severely lower casting's performance due to exceptions).

Upvotes: 7

Veverke
Veverke

Reputation: 11348

Years have passed... but minutes ago I came across a practical example I think is worth noting - of the difference between the two:

Check this out:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GenericCaster<string>(12345));
        Console.WriteLine(GenericCaster<object>(new { a = 100, b = "string" }) ?? "null");
        Console.WriteLine(GenericCaster<double>(20.4));

        //prints:
        //12345
        //null
        //20.4

        Console.WriteLine(GenericCaster2<string>(12345));
        Console.WriteLine(GenericCaster2<object>(new { a = 100, b = "string" }) ?? "null");

        //will not compile -> 20.4 does not comply due to the type constraint "T : class"
        //Console.WriteLine(GenericCaster2<double>(20.4));

        /*
         * Bottom line: GenericCaster2 will not work with struct types. GenericCaster will.
         */
    }

    static T GenericCaster<T>(object value, T defaultValue = default(T))
    {
        T castedValue;
        try
        {
            castedValue = (T) Convert.ChangeType(value, typeof(T));
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }

    static T GenericCaster2<T>(object value, T defaultValue = default(T)) where T : class
    {
        T castedValue;
        try
        {
            castedValue = Convert.ChangeType(value, typeof(T)) as T;
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }
}

Bottom line: GenericCaster2 will not work with struct types. GenericCaster will.

Upvotes: 0

Related Questions