var list = new List<object> { 1L, 6L, 4, 2L };
var sortedList = list.OrderBy(item => item).ToList();
上記のコードが実行されると例外が発生します。OrderByによるソートが実行された際にlong型でない値と比較しようとするためですが・・・
List<object>型なんぞ使わずにList<long>型でコンパイル時に安全が確認出来るようにするべきというのが、コーディング的には正しい方法だと思いますが、今回は、上記の実行時の挙動をもう少し観察したいと思います。
まず、デバック実行でわかる情報(プログラマが知り得る情報)を見てみたいと思います。

例外はArgumentExceptionで「オブジェクトは Int64 型でなければなりません。」というメッセージが表示されています。long型以外の型のオブジェクトが引数に渡されたため例外が発生したという事ですね。List<ojbect>型に対してOrderByしているのでobject型の比較でソートがかかるものだとおもったのですが、これは意外です。
さて更に細かく見ていきたいと思います。
System.ArgumentException はハンドルされませんでした。
Message="オブジェクトは Int64 型でなければなりません。"
Source="mscorlib"
StackTrace:
場所 System.Int64.CompareTo(Object value)
場所 System.Collections.Comparer.Compare(Object a, Object b)
場所 System.Collections.Generic.ObjectComparer`1.Compare(T x, T y)
場所 System.Linq.EnumerableSorter`2.CompareKeys(Int32 index1, Int32 index2)
場所 System.Linq.EnumerableSorter`1.QuickSort(Int32[] map, Int32 left, Int32 right)
場所 System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
場所 System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
場所 System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
場所 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
場所 Art55.OrderBy20100306.Program.Main(String[] args) 場所 C:¥Users¥art55¥Documents¥Visual Studio 2008¥Projects¥Art55.OrderBy20100306¥Art55.OrderBy20100306¥Program.cs:行 13
場所 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
場所 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
場所 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
場所 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
場所 System.Threading.ThreadHelper.ThreadStart()
InnerException:
上記は例外発生時のスタックトレースです。
上から順に詳しく見ていくと
場所 System.Int64.CompareTo(Object value)System.Int64構造体のCompareToメソッドが呼ばれていることがわかります。
恐らく6Lが格納されたSystem.Int64構造体のオブジェクトのCompareToメソッドに指定された引数がStystem.Int32構造体だったためArgumentExceptionが発生したものと推測されます。
場所 System.Collections.Comparer.Compare(Object a, Object b)
場所 System.Collections.Generic.ObjectComparer`1.Compare(T x, T y)
二つを同時に見てみます。ObjectComparer<T>のT型が一体何になっているのかきになるところですが、わかりません(恐らくobject型)。Compare(Object a, Object b)メソッドは公開されているメソッドなので、動作検証できます。
object o1 = 6L;
object o2 = 4;
Comparer.Default.Compare(o1, o2);
上記のコードでobject型同士の比較をしても、内部でlong型同士の比較が実行されるようで、同じようにArgumentExceptionが発生します。
MSDNライブラリーを覗いてみると
http://msdn.microsoft.com/ja-jp/library/system.collections.comparer.compare.aspx例外
ArgumentException
条件
a と b が、いずれも IComparable インターフェイスを実装していません。
または
a と b の型が異なっていて、両者を比較できません。
解説
a が IComparable を実装する場合は、a .CompareTo ( b ) が返されます。逆に、b が IComparable を実装する場合は、符号反転した b .CompareTo ( a ) が返されます。
nullNothingnullptrnull 参照 (Visual Basic では Nothing) を任意の型と比較できます。このような比較を行っても、IComparable を使用した場合に例外が生成されることはありません。並べ替え処理では、nullNothingnullptrnull 参照 (Visual Basic では Nothing) は、他のすべてのオブジェクトより小さいと見なされます。
文字列比較の結果は、カルチャに応じて異なる場合があります。カルチャ固有の比較の詳細については、System.Globalization 名前空間のトピックおよび「エンコーディングとローカリゼーション」を参照してください。
渡された引数のうちIComparebleが実装されているオブジェクトを選んで、CompareToメソッドを呼び出すという事がわかりました。
ブログをかいてる途中で、もやもや感が解消したので、ここでいったん止めます(笑)
--------------
追記
object o = 4;
long d = (long) o;
上記のようなキャストは実行時にエラーになるので
下記のような修正はできません。
var list = new List<object> { 1L, 6L, 4, 2L };
var sortedList = list.OrderBy(item => (long) item).ToList();
List<object>のリストを作成した意図がなんなのか考慮した上で修正する必要があります。
※実行時にエラーはでなくなるけど、意図した動きとは違う動きをしてしまう例(↓)
var list = new List<object> { 1L, 6L, 4, 2L };
var sortedList = list.OfType<long>().OrderBy(item => item).ToList();