views:

90

answers:

2

Why does this:

(new[]{1,2,3}).Cast<decimal>();

result in an

InvalidCastException: Specified cast is not valid.

+11  A: 

Yup, Cast doesn't do that. Basically it just does reference conversions and unboxing conversions - not conversions between different value types.

Use this instead:

(new[]{1,2,3}).Select(x => (decimal)x)

Note that pre-.NET 3.5 SP1, Cast did some more conversions than it does now. I don't know offhand whether it would have worked then or not, but it definitely doesn't now.

Jon Skeet
You're too fast. :)
David Morton
For some thoughts on why unboxing conversions from boxed int to unboxed decimal do not work, see http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx for details.
Eric Lippert
@Eric: I keep forgetting that `Cast` is on `IEnumerable` (and thus objects) rather than `IEnumerable<T>` - hence why it's an unboxing conversion rather than a conversion between two value types. (Not that a straight cast would work in that case). Mind you, I can *never* find the post where you explain about what `Cast` used to do (before SP1).
Jon Skeet
You can't find the one I wrote because I didn't write it. My manager Ed wrote it. http://blogs.msdn.com/ed_maurer/archive/2008/02/16/breaking-change-in-linq-queries-using-explicitly-typed-range-variables.aspx
Eric Lippert
@Eric: Ah. That would explain it. I thought there was one where you mentioned you were involved in reviewing the original code... or maybe that's someone else again...
Jon Skeet
Hmm. Maybe I did write something on that. I did review the original code and did not realize at the time that it was a reasonable implementation that was contrary to the specified design of the method, and incredibly slow to boot. (I thought we had changed the design; no, just the implementation!) It's unfortunate that we took a breaking binary change, but the perf gain and semantic correctness were judged to be worth the pain of the break. Perhaps I mentioned that in the blog at some point, or in a book review note.
Eric Lippert
+3  A: 

Cast isn't convert.

When you use the Cast extension method, it's trying to cast an item based on the inheritance scheme. Since int doesn't derive from decimal, this can't be done using Cast. Try the following instead:

(new[] {1,2,3}).Select(x => (decimal)X);
David Morton