少し更新が滞っていましたが、めげずにがんばります。今回は Shared キーワードのお話。
MSDNでは、
MSDN:Shared
(Visual Basic) (http://msdn2.microsoft.com/ja-jp/library/zc2b427x(VS.80).aspx)
宣言された 1 つ以上のプログラミング要素が、クラス全体または構造体全体に関連付けられ、クラスまたは構造体の特定のインスタンスに関連付けられないことを指定します。
Shared を使用する状況
クラスまたは構造体のメンバを共有すると、各インスタンスがメンバのコピーを別々に保持するのではなく、すべてのインスタンスがそのメンバを使用できます。このことは、たとえば、変数の値をアプリケーション全体で参照する場合に便利です。そのような変数を Shared で宣言した場合、すべてのインスタンスがストレージ内の同じ場所にアクセスするため、あるインスタンスが変数の値を変更すると、すべてのインスタンスが変更後の値にアクセスするようになります。
こんな感じ・・・ですね。(少し気になる言い回しもあるのですが・・・。)
要するに・・・Shared キーワードを使用して宣言された要素は、インスタンスを生成しなくてもクラス自体からアクセス可能ってことです。
たとえば、以下のような さくらクラス が在ったとして、
Imports System
Public Class さくら
Private Shared _花の色名 As String = "さくら色"
Public Shared ReadOnly Property 花の色名() As String
Get
Return _花の色名
End Get
End Property
End Class
花の色名プロパティは Shared プロパティなので、さくらクラス のインスタンスを生成しなくても、さくら.花の色名 といった記述でアクセスできますよ、と。
とはいえ、さくらクラス のインスタンス経由でもアクセスすることはできます。が、これにはおっかなびっくりな状況が起こりうるので気をつけなければいけません。以下、先ほどの さくらクラス を使用したおっかなびっくりサンプルコードです。
Imports System
Imports System.Windows.Forms
Public Class さくら
Private Shared _花の色名 As String = "さくら色"
Public Shared ReadOnly Property 花の色名() As String
Get
Return _花の色名
End Get
End Property
End Class
Public Class さくら屋さん
Public Function さくらのインスタンスを生成する() As さくら
MessageBox.Show("さくらのインスタンスを生成しようとしているよ。")
Return New さくら
End Function
End Class
Public Class 錯乱プログラム
Public Shared Sub Main()
Dim さくら屋 As New さくら屋さん
MessageBox.Show("さくらの花の色は、" & さくら屋.さくらのインスタンスを生成する().花の色名() & "です。")
MessageBox.Show("そのまんまでんがな!")
End Sub
End Class
先ほどの さくらクラスに加え、さくら屋さんクラス と、エントリポイントを持つ 錯乱プログラムクラス を作成しました。
実行したときの流れを見たまま追いかけると・・・
- さくら屋さん クラスのインスタンスを生成する。
- さくら屋さん クラスのインスタンスの 'さくらのインスタンスを生成する' メソッドで取得したさくらクラスのインスタンス経由で花の色名を取得して出力する。
(さくら屋さんのインスタンスは'さくらのインスタンスを生成する' メソッドが呼ばれると、「さくらのインスタンスを生成しようとしているよ。」とつぶやく。)
- ツッコミを入れる。
しかし、いざ実行してみるとこうはなりません。試してみると分かりますが、さくら屋さんのつぶやき(「さくらのインスタンスを生成しようとしているよ。」)は表示されません。おかしいですねぇ。
と、いうことで調べました。このあたりの情報もMSDNにありましたよ。さきほどのMSDNのShared キーワードへのリンク先の中のこの一文↓
インスタンス式を使用したアクセス
クラスや構造体のインスタンスを返す式を使用して共有要素にアクセスした場合、コンパイラは式を評価せず、クラス名や構造体名を使ってアクセスします。この式を使ってインスタンスを返す他に何か別の処理も実行しようとしていた場合は、予期しない結果になります。
つまり、インスタンス経由で Shared メンバにアクセスするコードを書いていてもコンパイラは無視して、直接クラス名や構造体名を使って処理しちゃうの、ってことですね。上のサンプルコードでいうと、
さくら屋.さくらのインスタンス().花の色名()
の部分は、
さくら.花の色名()
として解釈されるということです。さくら屋さんクラスの'さくらのインスタンスを生成する()'は呼ばれていないので、さくら屋さんのつぶやきは表示されないんですね。
さくら屋さん、出る幕無し!
もちろんコンパイラも意思表示はしてくれます。規定では警告になっていますが、以下の内容が出力されます。
インスタンスを経由する共有メンバ、定数メンバ、列挙型メンバ、または入れ子にされた型へのアクセスです。正規の式は評価されません。
・・・気をつけます。m(_ _;)m