この記事で述べていること
- is演算子でのキャストは結果がtrueになる際のみ行われます。ですが、結果に関係なくキャスト後の変数の宣言はなされます(falseの場合中身は未初期化になる)
- また、ifステートメントの条件式内でis演算子を用いてキャストすると、キャスト後の変数のスコープはそのifを囲むブロック内となります。
- この性質のせいで、早期returnで弾くと同時にキャストし、キャスト後の変数をその後使おうとすると怒られます。
- そういう時はasとnullチェックを使いましょう。
説明
is演算子を使ってifステートメントの条件式内でキャストを行った場合、キャスト後の変数のスコープはそのifを囲むブロック内となります。
また、is演算子でのキャストはインスタンスの型が一致した場合のみ行われます。一致しない場合変数は宣言されますが、中身は未初期化になります(nullが入るわけでもありません)
この性質のせいで、早期returnでインスタンスの型が一致しない場合を弾いた後、キャスト後の変数を後々の処理に使おうとするとちょっと問題が生じます。
インスタンスの型チェックと早期return
public void hoge(Object obj){
//こうしてobjのインスタンスの型が任意の型でない場合を弾いた後
if((obj is int x) == false) return;
//後々の処理にxを使おうとすると
//未初期化の可能性があると言われ怒られる
Console.WriteLine(x);
//同名変数の再宣言も不可で怒られる
int x = 1;
}
コンパイラから見たらintじゃない場合最初のifで弾かれてるからifの外で使っても大丈夫なんてわからないので、怒られます。
かといって変数が死んでいるわけではないので、同名変数の再宣言も不可です。怒られます。
考えてみれば当たり前の話で馬鹿らしいですが、私はこれで数十分無駄にしました。
解決策
ではどうするか。as演算子とnullチェックを組み合わせましょう。
as演算子との組み合わせ
public void hoge(Object obj){
int x = obj as int;
if(x == null) return;
//怒られずにnullチェック済みのxを使って処理が可能
Console.WriteLine(x);
}
これで解決ですね。
最後に
マサカリお待ちしてます。
参考サイト
- is、switch の拡張 (型スイッチ)
https://ufcpp.net/study/csharp/datatype/typeswitch/ - [雑記] 識別子のスコープとオブジェクトの寿命
https://ufcpp.net/study/csharp/start/st_scope/?p=3#declaration-expressions