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

表題のとおり。
LINQのCast<TResult>でint→longとかint→shortとか、
その他数値間のキャストをしようとすると
InvalidCastExceptionで落ちる。最近知った。
OfType<TResult>()だとエラーにはならないが、要素が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();

 
 
以上。