C#のキャスト

C#のキャストについてです。
よくあるFormアプリのイベントハンドラで下記のようなものがあります。

private void ButtonClick(object sender, EventArgs e)
{
...
}

引数のsenderはイベントを発行したインスタンスが入ります。
このメソッドを複数のボタンのクリックイベントに紐付けた場合、下記のようにボタンにキャストしてプロパティを参照するのをよく見かけます。

private void ButtonClick(object sender, EventArgs e) 
{
    string name = ((Button)sender).Name;
}

これはsenderがnullの場合やボタンではない場合に例外が発生します。
このButtonClickメソッド自体は直接呼ぶこともできるし、ボタンのクリックイベントだけでなく他のイベントや他のコントロールのイベントにも型さえあえば設定できるため、senderは必ずしもButtonのインスタンスが入っているとは限りません。

そこで下記のような書き方ができます。

private void ButtonClick(object sender, EventArgs e) 
{
    Button button = sender as Button;
    if (button != null)
    {
        string name = button.Name;
    }
}

asを使ってsenderをButtonとして取得しています。
Buttonであればbuttonに代入され、Buttonでなければnullとなります。
なので直後にnullでないことを確認してからプロパティにアクセスしています。
この方法なら例外は発生しません。

プロパティにアクセスする必要がなく、Buttonかどうかが知りたいだけなら、下記のようにもできます。

private void ButtonClick(object sender, EventArgs e) 
{
    if (sender is Button)
    {
        ...
    }
}

isはsenderがButtonまたはその派生クラスの場合にtrueとなります。
それ以外やnullの場合はfalseになります。

また、古いバージョンでは使えませんが、下記のように同時に代入もできます。

private void ButtonClick(object sender, EventArgs e) 
{
    if (sender is Button button)
    {
        string name = button.Name;
    }
}

isでtrueの場合はそのインスタンスがbuttonに代入されるので、そのままプロパティにもアクセスできます。
asで変換してnullかどうか見るよりはこちらのほうが良いです。

ただ、ButtonならNameプロパティを、Buttonでないなら別の値を、ということをしたい場合はasで下記のように書くこともできます。

private void ButtonClick(object sender, EventArgs e) 
{
    string name = (sender as Button)?.Name ?? "abc";
}

asで取得した結果に ?. をつけることで、ButtonであればNameを、そうでなければnullとなり、さらに ?? をつけることで、nullであれば “abc” を取得できます。

asかisかはその時々にあうほうでよいかと思いますが、少なくとも直接キャストするのはやめましょう、という話です。

スポンサーリンク