何かと便利なObject型の定義
オブジェクト型で定義をすれば何でも使えます。 任意の参照型で文字列、配列、クラスなどをオブジェクト変数に割り当てることができます。 例えばこんな感じです。
1 2 3 4 5 6 7 8 9 10 11 |
Dim aaa As Object = Nothing Dim bbb As Object = Nothing aaa = 1 bbb = 2 aaa = "String aaa" bbb = "String bbb" aaa = New Button bbb = New Class1 |
以上の使い方でも、エラーとはなりません。
問題の例外処理
ここで本題です。例外の再スローをクラス間でしようと思ったときにエラーがうまく捕捉されないという状況です。まずは、問題のない状態からです。
1 2 3 4 5 6 7 8 9 10 11 12 |
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim ClassA As New Class1 Try ClassA.ddd() Catch ex As Exception Dim st As StackTrace = New System.Diagnostics.StackTrace(ex, True) MsgBox(ex.TargetSite.DeclaringType.Name + ":" + ex.TargetSite.Name + ":" + st.GetFrame(0).GetFileLineNumber(), vbOKOnly, "") End Try End Sub |
22行目の書きようでは「非共有メンバを参照するには、オブジェクト参照が必要です」のエラーが出るため、19行目でClass1のインスタンスを作成します。
そして、呼び出すクラス「Class1」は以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Public Class Class1 Private sss As Integer = 0 Private fff As Integer = 0 Public Sub ddd() Try vvv() Catch ex As Exception Throw End Try End Sub Private Sub vvv() Dim ggg As Integer = sss \ fff End Sub End Class |
ここで、Class1のddd()はPrivateではアクセスできないためPublicにしています。
さて、結果がこちらです。
特に作成意図通りで問題はありません。
続いて、インスタンスを始めにObject型で宣言した場合です。
1 2 3 4 5 6 7 8 9 10 11 12 |
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim ClassA As Object = New Class1 Try ClassA.ddd() Catch ex As Exception Dim st As StackTrace = New System.Diagnostics.StackTrace(ex, True) MsgBox(ex.TargetSite.DeclaringType.Name + ":" + ex.TargetSite.Name + ":" + st.GetFrame(0).GetFileLineNumber(), vbOKOnly, "") End Try End Sub |
Class1の方は同じですがこれを実行とするとこうなります。
メッセージには出ずに Class1のddd()のCatch部の再スローのところで途中で止まってしまいます。(※実行時はDebugモード)
なぜだろうと思い、もとの呼び出し部の「ClassA.ddd()」の参照を見てみると、 通常であれば以下のような参照が出ていたのですが、 参照がなくなっています。
困りました。オブジェクト型で定義したことがいけなかったのでしょうか。
オブジェクト型も便利なので、例えば、こんな感じで一般汎用型としてこんな感じで考えていました。
使いみちとしては、条件でクラスを変えたいときなどに考えるアイデアですかね。
1 2 3 4 5 6 7 |
Dim ClassA As Object = Nothing If aaa = 1 Then ClassA = New Class1 Else ClassA = New Class2 End If |
これができないのかと思い調べてみたら、これは「遅延バインディング」というやつらしいです。
遅延バインディングは、オブジェクトに変数を代入するときに、実際に代入されるまでオブジェクトの型が分からない場合が対象になります。
暗黙の型変換としてデフォルトはオフになっていますが、ファイルの一番上に「Option Strict On」と書けばそれがオンになり、先程の 「ClassA.ddd()」 が遅延バインディングとしてエラーとなります。
エラーが出た書き方では、処理時にずっとObject型のままであるためだったことが原因だったということなので、型変換を明示的にすれば良いですね。
つまりは以下のようにすれば、エラーはなくなり参照はつながってくれます。
1 |
DirectCast(ClassA, Class1).ddd() |
これで途中で止まることはなくなりました。
型変換についてはこれ以外にも方法はありそうですかね。
メリットとデメリットまとめ
そんなオブジェクト型のメリットは、あらゆる場合で何でも使える便利なものと言えますが、デメリットとして、定義した型の本来の使い方(型)が不明になったりする。そんなミス防止と処理速度にもかなり影響があるらしいです。
結局、 Object型は使用時にはきちんと型変換して使う、もしくは、始めからその型を宣言してから使いなさいという「事前バインディング」をすることが推奨されているということです。
もし使うのであれば、 オブジェクト型以外ではどうしても使えないときなど、限定的な使い方にしたほうが、バグ防止や管理する側としても良いような気がします。
コメント