1. ホーム
  2. c#

[解決済み] なぜC#では'nullを投げる'ことができるのか?

2023-04-07 05:27:07

質問

特に複雑な例外処理コードを書いているとき、ある人が、例外オブジェクトがヌルでないことを確認する必要はないのですか、と尋ねました。 そして私は、もちろん必要ないと言いましたが、その後、試してみることにしました。 どうやら、null を投げることはできますが、それはまだどこかで例外に変わります。

なぜこれが許されるのでしょうか?

throw null;

このスニペットでは、ありがたいことに'ex'はnullではありませんが、果たしてそうでしょうか?

try
{
  throw null;
}
catch (Exception ex)
{
  //can ex ever be null?

  //thankfully, it isn't null, but is
  //ex is System.NullReferenceException
}

どのように解決するのですか?

言語仕様では、型が System.Exception がある(したがって null はそのコンテキストでは有効です)、この式が非NULLであることを制限していません。一般に、その式の値が null であるかどうかを検出することはできません。halting problemを解決しなければならないだろう。ランタイムは null のケースを扱わなければならない。見てください。

Exception ex = null;
if (conditionThatDependsOnSomeInput) 
    ex = new Exception();
throw ex; 

を投げるという具体的なケースを作ることも、もちろんできるだろう。 null リテラルを無効とすることもできますが、それではあまり意味がありませんし、わずかな利益のために仕様スペースを浪費し、一貫性を低下させるのはいかがなものでしょうか。

免責事項(Eric Lippertに叩かれる前に)。これは 私自身の の推測に過ぎません。もちろん、私は設計会議に出席したことはありません ;)


2つ目の質問、catch節内でキャッチされた式変数は絶対にnullになることがあるのか、に対する回答です。C#の仕様では、他の言語がcatch節で捕捉された式変数をnullにできるかどうかについては言及されていません。 null 例外を伝播させることができるかどうかについて、C#の仕様は沈黙していますが、例外を伝播させる方法は定義しています。

catch節は、もしあれば、例外に適したハンドラを見つけるために、出現順に調べられます。最初のcatch節は で、例外の型または例外の型の基底型を指定します。 はマッチするとみなされます。一般的なcatch節は、どのような例外型に対してもマッチするとみなされます。[...]

については null については、太字の記述は誤りです。したがって、C# の仕様に純粋に基づくと、基礎となるランタイムが決して null を投げないとは言えませんが、たとえそうであったとしても、それは一般的な catch {} 節によってのみ処理されることを確認できます。

CLI上のC#実装については、ECMA 335仕様を参照することができます。その文書では、CLIが内部で投げるすべての例外を定義しています(いずれも null によって投げられるユーザー定義の例外オブジェクトについて言及しています。 throw 命令で投げられることに言及しています。その命令に対する記述は、実質的にC#の throw 文とほぼ同じです(オブジェクトの型を制限しないことを除けば System.Exception ):

説明

throw 命令は例外オブジェクトを投げます (タイプ O ) を投げ、スタックを空にする。例外の仕組みの詳細については、Partition Iを参照してください。

[注:CLIではどのようなオブジェクトでも投げることができるが、CLSでは言語の相互運用性のために使用しなければならない特定の例外クラスが記述されている。 注を終了する]。

例外です。

System.NullReferenceException が投げられた場合 objnull .

正しさ

正しいCILは、オブジェクトが常に以下のいずれかであることを保証します。 null またはオブジェクトの参照(つまり、型 O ).

捕捉された例外は決して null .