OITA: Oika's Information Technological Activities

@oika 情報技術的活動日誌。

C# IEnumerable.Castメソッドでint→longはできない

表題のとおり。
LINQのCastでint→longとかint→shortとか、
その他数値間のキャストをしようとすると
InvalidCastExceptionで落ちる。最近知った。
OfType()だとエラーにはならないが、要素が1つも返ってこない。

コードは以下。

int[] ints = new [] { 1, 2, 3 };  
long[] longs = ints.Cast<long>().ToArray(); //throws InvalidCastException  

ToArray()はクエリを実行させるために入れてるだけなので何でも良い。

んで、理由はCastメソッドの実体を覗くとよくわかる。
(ILSpyで見たもの)

// System.Linq.Enumerable  
private static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)  
{  
 foreach (object current in source)  
 {  
  yield return (TResult)((object)current);  
 }  
 yield break;  
}  

このCastメソッドはジェネリックでないIEnumerableの拡張メソッドなので
いったんobject型にキャストしてから目的の型にキャストしてるわけだ。
このobjectへのキャストのときにボックス化が起きてしまって、
ボックス化解除のときに型が一致しないので失敗する。
詳しくはMSDNの説明参照 →ボックス化解除変換

そんなわけで、Castの代わりにSelectメソッドとか使いましょう。

int[] ints = new [] { 1, 2, 3 };  
long[] longs = ints.Select(i => (long)i).ToArray();  

 
以上。