3

I have following code snippet in c#

List<int> list = new List<int>() { 1, 23, 5, 3, 423, 3 };
            var query = list.Cast<double>().Select(d => d);
            try
            {
                foreach (var item in query)
                {
                    Console.WriteLine(item);

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

            }

It's compile perfectly,but when i am executing this I am getting exception.

razlebe
  • 7,134
  • 6
  • 42
  • 57
santosh singh
  • 27,666
  • 26
  • 83
  • 129

3 Answers3

10

Because you're typecasting from an int to double, it's not a conversion it's a type cast and this is somewhat different from when you cast int to double in the general case.

The Cast<T> extension method uses the IL instruction unbox.any

While a C# cast like this

var x = (double)42;

Actually results in the IL instruction

conv.r8 

Fundamentally unboxing an type as a different type is wrong and that's why you get the exception.

This question has the same answer and also links to a blog post by Eric Lippert.

Community
  • 1
  • 1
John Leidegren
  • 59,920
  • 20
  • 131
  • 152
6

list contains ints, which you attempt to cast to double. Change your query to

var query = list.Select(d => (double)d);

Update

Here's the source for Enumerable.Cast (.NET 4):

public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { 
    IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
    if (typedSource != null) return typedSource; 
    if (source == null) throw Error.ArgumentNull("source");
    return CastIterator<TResult>(source);
}

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
    foreach (object obj in source) yield return (TResult)obj; 
} 

As you can see, the CastIterator attempts to cast an object (which in this case is a boxed int) to a double. Unboxing operations only succeed if the target type is exactly the same as the original type that was boxed, so an exception is thrown. This link that John Leidegren provided explains in detail.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • but I am using Cast extension method. – santosh singh Mar 15 '11 at 09:02
  • 1
    Jon: I didn't downvote, but it seems this is incorrect, if you look at John's answer (and Lex's linked post). You'll note in the pasted code that the cast from `IEnumerable` to `IEnumerable` will only be attempted as a fast path. The actual error is because you can't cast from `object` (boxed `int`) to `double`, which happens inside the `Enumerable` returned by `CastIterator`. – porges Mar 15 '11 at 09:37
  • 1
    @Porges: Thanks! That should teach me to write before having morning coffee. Corrected the answer. – Jon Mar 15 '11 at 09:42
2

There is a difference between a .NET Framework type-cast and a C# type conversion. They are NOT the same. "Casting" int to double is a feature of the C# language, and of the language alone.

The C# compiler can convert an int to double using a special instruction for this purpose. The compiler knows, at compile time, that the source type is "int", the destination type is "double", and therefore can generate the proper instruction. This is not really a type cast in the .NET Framework sense.

System.Int32 cannot be type-cast to System.Double. The Cast extension method was compiled without knowing the exact types of the source and the destination collections, and therefore no special instructions for handling C# specific features were generated. The only code that is generated for the Cast extension method is a normal .NET type cast (casting classes to their base types, casting to object, and casting types to the interfaces they implement).

Alex Shtoff
  • 2,520
  • 1
  • 25
  • 53