.Net 2+:if( 1 == null ) がコンパイラ例外をスローしなくなったのはなぜですか?
-
09-06-2019 - |
質問
使っています int
これは例ですが、これは .Net のすべての値の型に当てはまります。
.Net 1 では、次のコードはコンパイラ例外をスローします。
int i = SomeFunctionThatReturnsInt();
if( i == null ) //compiler exception here
現在 (.Net 2 または 3.5 では) その例外はなくなりました。
その理由はわかっています:
int? j = null; //nullable int
if( i == j ) //this shouldn't throw an exception
問題は、 int?
null 可能であり、 int
暗黙的にキャストされています int?
. 。上記の構文はコンパイラの魔法です。実際に私たちは次のことを行っています:
Nullable<int> j = null; //nullable int
//compiler is smart enough to do this
if( (Nullable<int>) i == j)
//and not this
if( i == (int) j)
それで、今、私たちがそうするとき、 i == null
我々が得る:
if( (Nullable<int>) i == null )
C# がこれを計算するためにコンパイラ ロジックを実行していることを考えると、次のような絶対値を扱うときにそれを行わないほど賢明ではないのはなぜでしょうか。 null
?
解決
これはコンパイラの問題ではないと思います それ自体;整数値が null になることはありませんが、それらを同等に扱うという考え方は無効ではありません。これは常に false を返す有効な関数です。そしてコンパイラはそれを知っています。コード
bool oneIsNull = 1 == null;
コンパイルは完了しますが、コンパイラ警告が表示されます。 The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type '<null>'
.
したがって、コンパイラ エラーを元に戻したい場合は、プロジェクトのプロパティに移動し、このエラーに対して「警告をエラーとして扱う」をオンにすると、再びビルドを妨げる問題として認識されるようになります。
他のヒント
奇数 ...これを .NET 3.5 をターゲットにして VS2008 でコンパイルします。
static int F()
{
return 42;
}
static void Main(string[] args)
{
int i = F();
if (i == null)
{
}
}
コンパイラの警告が表示される
warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'
そして、次のILを生成します...おそらく JIT によって最適化されなくなるでしょう。
L_0001: call int32 ConsoleApplication1.Program::F()
L_0006: stloc.0
L_0007: ldc.i4.0
L_0008: ldc.i4.0
L_0009: ceq
L_000b: stloc.1
L_000c: br.s L_000e
コードスニペットを投稿していただけますか?
null 非許容型と null を比較すると、コンパイラは引き続き警告を生成しますが、これは本来あるべき姿です。警告レベルが低すぎるか、最近のバージョンで変更された可能性があります (私は .net 3.5 でのみ変更しました)。
2.0 フレームワークでは、null 許容値型が導入されました。リテラル定数「1」を null にすることはできませんが、その基になる型 (int) を Nullable int 型にキャストできるようになりました。私の推測では、コンパイラは、たとえそれがリテラル定数であっても、int 型が null 許容ではないと想定できなくなったのではないかと思います。2.0 をコンパイルするときに警告が表示されます。
警告 1 'int' 型の値は 'int?' 型の 'null' と等しくないため、式の結果は常に 'false' になります。
警告は新しいものです (3.5 だと思います) - エラーは、私が実行した場合と同じです 1 == 2
, 、それは決して真実ではないことを見分けるのに十分賢いです。
完全な 3.5 最適化では、真の評価がまったくない非常にスマートなため、ステートメント全体が単に削除されるのではないかと思います。
欲しいかも知れませんが 1==2
コンパイルする (たとえば、他のものをテストしている間、関数ブロックをオフにする) 必要はありません 1==null
に。
型に互換性がない (値の型を null にすることはできない) ため、これはコンパイル時エラーであるはずです。そうじゃないのはかなり残念だ。