雑記 - otherwise

最近はDQ10しかやっていないダメ技術者がちまちまと綴る雑記帳

続続・ nullable な引数を持つメソッドをオーバーロードする場合の解決

コメントの中で aetos さんが提示されている例について考えてみようと思います。

前提

この例での引数は 0 と云う定数です。
この定数は byte, byte?, short, short? のいずれにも暗黙的に変換が可能なので、これらの型を引数とする関数すべてがオーバーロード解決の対象となります。

前提 2

nullable な型の変換については、言語仕様 (C#3.0) の「 6.1.4 暗黙の null 許容変換」に記載があります。

null 非許容の値型を操作する定義済みの暗黙の変換は、それらの型の null 許容形式に対しても使用できます。null 非許容の値型 S を null 非許容の値型 T に変換する定義済みの暗黙の恒等変換および数値変換のそれぞれについて、次のような暗黙の null 許容変換が存在します。

  • S? から T? への暗黙の変換
  • S から T? への暗黙の変換

S から T への基になる変換に基づく暗黙の null 許容変換の評価は、次のように処理されます。

  • S? から T? への null 許容変換の場合は、次のように処理されます。
    • ソース値が null (HasValue プロパティが false) の場合、結果は型 T? の null 値になります。
    • それ以外の場合は、変換を S? から S へのラップ解除として評価し、引き続き S から T への基になる変換を実行して、T から T? へのラップを実行します。
  • S から T? への null 許容変換の場合は、変換を S から T への基になる変換として評価し、引き続き T から T? へのラップを実行します。

また、 null から nullable 型への変換については、「 6.1.5 null リテラル変換」に記載があります。

null リテラルから任意の null 許容型への暗黙の変換が存在します。この変換は、指定した null 許容型の null 値を生成します。

ケース 1 (byte vs. short)

引数の型が限定的なものが適切な関数として採用されるので、 short より限定的な型である byte が選択されます。
これは良く知られた動作ですし、特に問題はないと思います。

ケース 2 (byte vs. short?)

前提 2 で述べた様に、 S → T? の変換規則は S → T の変換規則と同じと判断出来ます。
従って、このケースはケース 1 と同じです。

ケース 4 (byte? vs. short?)

こちらもケース 2 と同様ですね。

ケース 3 (byte? vs. short)

さて、問題はこのケース 3 ですが、そもそも byte? と short の間には、どちらの方向にも暗黙的な型変換が存在しないので、オーバーロードの解決が出来ません。
なのでコンパイルエラーになります。