isでキャストでおきるエラーを減らそう

asを使ってエラー、キャスト式「()を使ったキャスト」を使ってエラー
と型変換とエラーにお困りの方向けの記事です。

キャストするロジックを組むと実行時にエラーが発生して困ることはありませんか。

C#のキャスト方法は複数あって、asを利用したキャスト
(int)のように()を使ったキャスト式によるキャストがあります。

それぞれのキャスト方法には特徴があり、
エラーを発生させるパターンが異なります。

今回は、どちらのキャスト方法でも使えるエラー対策について紹介します。

isでキャストでおきるエラーを減らそう

結論から行きます。

キャストするときにはasを利用するにしろキャスト式を利用するにしろ

  • isを使ってキャストできるか判定

です。

なぜisを利用するとよいのか。次の項目ごとに紹介します。

  • isは事前にキャストできるか確認できる
  • キャスト式でエラーになる理由
  • キャスト式の代わりにasを使うと今度はコンパイルエラー
  • 実行時エラーもコンパイルエラーもisで解決

isは事前にキャストできるか確認できる

キャストできるかのチェックはisでやるとコンパイルエラーもしくは実行時エラーを防ぐことができます。

isでチェックしたあとにキャスト式もしくはasでキャストすると実行時エラーの可能性はなくなるでしょう。


キャスト式でエラーになる理由


上記のような、キャスト式が実行時にエラーになるのは2つの理由があります。

理由の一つは、Nullが入ってくることです。

キャスト式の内部でnullを参照してエラー

Cannot convert null to ‘int’ because it is a non-nullable value type

これは値型でよく起こります。

もう一つは、変換できない値が入ってきたときエラー。

Cannot convert type ‘int’ to ‘●●”

例えば、Listに変換したいときに、数値型の「10」がくれば、

キャストに失敗してエラーになります。

キャスト式の代わりにasを使うと今度はコンパイルエラー

変換できなかったときにすべてNullにしてくれる便利な機能としてasがあります。

キャスト式でエラーになる変換も、asならエラーになりません。


変換できないものはすべてNullにしてくれるため、

asで変換後にnullチェックをすれば、キャストがうまくいった場合のみ処理をすることができます。

しかし、このasも万能ではありません。

asでコンパイルエラーになるパターン

asを利用するとき、キャストに失敗したならばNullになる特徴があることを説明しました。

このキャスト先がNullに変換できるかどうかは重要なポイントです。

というのも、キャスト先の型がNullをサポートしていない型(主に値型)の場合は、
変換失敗時に確実にエラーなることがわかっているため、コンパイルエラーが起きるのです。

エラー CS0077
as 演算子は参照型または null 許容型で使用してください (‘double’ は null 非許容の値型です)

型チェックでasを使うコードがある理由

型チェックでasを使うコードがある理由は単純で、ちょっと前までisがなかったんですよね。

C# 7.0 以降では、変換が成功するかどうかのテストと、
成功する場合の新しい変数への結果の代入の両方を、is 演算子を使って行うことができます。

実行時エラーもコンパイルエラーもisで解決

isをつかってif文で処理する前提ならば、キャストが約束されているので、
キャスト式でも、コンパイルエラーがでないならasも利用できます。

asもキャスト式もisと一緒に使うことをお勧めします。

値型でもisで対処

asによる判定はキャスト先が値型の時はコンパイルエラーでうまくキャストと判定ができませんでした。

しかし、isを使えば解決します。

冒頭の例を見てみましょう。


実践で出てくるisを使ったキャスト例

こちらの記事で属性のキャストを題材にis利用をしています。

興味がありましたらご覧ください。

>>属性を取り出して処理する

isの弱点と対策

  • isで判断できないキャストがある
  • isで判断できないキャストでもisを使う理由

isに弱点はないのかといわれるとそうではありません。

isには判定できないキャストが実はあります。

しかし、isの使い方次第でisが判定できないキャストにも対応できます。

一つずつみていきましょう。

isで判断できないキャストがある

キャスト元とキャスト先が、「互換性のない型」はisで検出できません。

ここでいう「互換性」とは、継承やインターフェースを指します。

自分でキャスト式の変換を定義できるがゆえに、
キャスト式は定義の仕方によって、互換性のない型への変換を行います。

なじみのある例をとりましょう。


doubleはintを持っていませんが、事前にintに変換するための仕組みが定義されているので
キャスト式を使えば、intに変換することができます。

しかし、isで確認できるのは、継承や所持しているインターフェースなど互換性があるものに限られます。

互換性のものを持っているかをチェックするため、

異なる型への変換に相当するキャストは対応できないです。

では、実際にisの判定結果がどうなるか見ていきましょう。

isによる互換性チェックの結果

doubleとintはともに数値型・値型などなど共通のインターフェースをもっています。

isでのdoubleとintの値型チェックはいつでも「true」です。


それぞれ共通で所持している値型(ValueType)への変換は問題なくできます。

しかし、doubleはintの派生ではありませんし、逆もまたしかりです。


「doubleはintを持っていない」

つまり、doubleはintの派生でもなければintのインターフェイスももっていません。

あくまで、isはどんなクラスやインターフェースを持っているかの互換性を判断しています。

完全に違うものに型変換できるかは判断していませんので、注意が必要です。

isで判断できないキャストでもisを使う理由

isで判断できないキャストがあることを紹介しましたが、それでもisを使うことで対応できます。

キャスト先ではなく、キャスト元で判断すれば問題ありません。

もしintへキャストしたいものとしてdoubleがあれば

doubleで判定してintに変換するようなコードにすれば解決します。


キャストできるか?よりも決め打ちになるため、範囲は狭いのは難点ですね。

しかし、エラーを発生を発生させず安全にキャストできる利点があることからも、isはやはり有効です。

まとめ

最後に、今回の記事をまとめます。

  • isを使ってキャストできるか判定
  • 型に関連のないキャストはisをキャスト元に使用する

isを利用すれば、キャストに関連するエラーを減らすことができますので、

キャストをする場面があれば、利用してみてください。

では。