tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルプロパティの定義方法で疑問
記事No7751
投稿日: 2008/06/28(Sat) 21:39
投稿者ダンボ
VB,net文法で、わけが分からなくなったので、解説お願いします。

2つのプロパティ(OpenProp、CloseProp)を定義した場合、
Public Class TestClass
    Public OpenProp As Integer
    Private _CloseProp As Integer
    Public Property CloseProp() As Integer
        Get
            Return _CloseProp
        End Get
        Set(ByVal value As Integer)
            _CloseProp = value
        End Set
    End Property
End Class
Public Class Test
    Dim Testobj As TestClass = New TestClass
    Testobj.OpenProp=1      '←この文はエラー「宣言が必要です。」
    Testobj.CloseProp=2     '←この文はエラー「宣言が必要です。」
    Dim i As Integer = Testobj.OpenProp     '文法エラーにはならない
    Dim j As Integer = Testobj.CloseProp    '文法エラーにはならない
End Class

質問1:なんでコンパイルエラーになるのでしょうか?
質問2:プロパティを使う側としては、OpenPropもClosePropも使い勝手は同じなのに
   なぜ2通りの書き方ができるのでしょうか?どんな違いがあるのでしょうか?

[ツリー表示へ]
タイトルRe: プロパティの定義方法で疑問
記事No7755
投稿日: 2008/06/29(Sun) 21:57
投稿者魔界の仮面弁士
> 2つのプロパティ(OpenProp、CloseProp)を定義した場合、
CloseProp の方はプロパティですが、
OpenProp はプロパティではなく、フィールド変数です。


>     Testobj.OpenProp=1      '←この文はエラー「宣言が必要です。」
>     Testobj.CloseProp=2     '←この文はエラー「宣言が必要です。」
クラスの直下に、このような処理を書くことはできません。
Sub / Function などのプロシージャ内部で行うようにしてください。

>     Dim i As Integer = Testobj.OpenProp     '文法エラーにはならない
>     Dim j As Integer = Testobj.CloseProp    '文法エラーにはならない
これらは、フィールド変数の初期値を設定しているだけなので、
その前の 2 行とは意味合いが異なります。

ただ、初期化の順番を保証するためにも、Testobj のプロパティを呼び出すなら、
Test クラス側にコンストラクタを設けて、その中で初期化処理を行うべきかと。


> 質問1:なんでコンパイルエラーになるのでしょうか?
クラスの直下におけるのは「宣言」だけだからです。
(Dim ステートメントは、フィールド変数の宣言として扱われます)


> 質問2:プロパティを使う側としては、OpenPropもClosePropも使い勝手は同じなのに
>    なぜ2通りの書き方ができるのでしょうか?どんな違いがあるのでしょうか?
Private な場合は、どちらでも構いません。
プロパティでは冗長的な場合には、フィールド変数にしておけば十分かと思います。

Public な場合は、常にプロパティを使用すべきです。
フィールド変数を Public にするのは、ReadOnly な場合だけにしておきましょう。

で、違いとしては…プロパティとして実装されていれば、
 「Text プロパティが変更されたら、TextChanged イベントを発生させる」
 「Month プロパティには、1〜12 の値しか代入させない」
といった機能を組み込むことができますが、フィールド変数ではそれができませんね。

使い方が同じだから、どちらでも同じ機能であるかのように見えてしまいますが、
後から実装方法を変えるのは、互換性が失われるので避けた方が良いかも知れません。
たとえば、データバインドなどのように、リフレクションによる実装が行われて
いる場合には、クラス側にはフィールド変数ではなく、プロパティとしての実装が
求められる事もあったりします。

[ツリー表示へ]
タイトル[解決] プロパティの定義方法で疑問
記事No7756
投稿日: 2008/06/30(Mon) 09:52
投稿者ダンボ
魔界の仮面弁士さん、いつもどうも有り難うございます。

よく分かりました。
何がどう分かったのかを(突っ込みどころ満載で)記してみましたので更にご指摘があればよろしくお願いします。

教訓1.クラス文の直下に書けるものは宣言(定義)文だけ
自己流解釈
・クラス文はクラスの(型)定義をするものであり、実行されるわけではない。直下に実行文を
 書いても実行するタイミングは無いから文法エラーにしておいたほうが良い。
・そう言えば、SubもFunctionもPropertyもDimも宣言(定義)文だった。
・ならば、Public Dim ABC As XXX、Private Dim ABC As XXXと書ける筈だ。しかし
 Dimだけは省略必須らしくPublic ABC As XXX、Private ABC As XXXと書き直された。

教訓2.PublicクラスのPublicなフィールド変数はプロパティのように使える。
自己流解釈
・誰からも存在が認識できるクラスオブジェクトの誰からも読み書きできる変数だからそうなる。
・クラスが構造体からの発展だと考えれば当たり前。
・よってPublicなフィールド変数は(広義のプロパティ)と考えても良い。
・では本当のプロパティのメリットは、
 (1)ReadOnly、WriteOnlyなどの制限を設けることができる。
 (2)ロジックを含めることができる。下記の例はフィールド変数への書き込みではできない。
    Public Property Modified() As Boolean
        Get
            Return innerModified
        End Get
        Set(ByVal value As Boolean)
            innerModified = value
            If value Then
                innerProfile.LastModifyDate = Now
                RaiseEvent Updated(Me, New EventArgs)
            End If
        End Set
    End Property


> Public な場合は、常にプロパティを使用すべきです。
> フィールド変数を Public にするのは、ReadOnly な場合だけにしておきましょう。
→このお作法のメリットが理解できません。(泣)

[ツリー表示へ]
タイトルRe: [解決] プロパティの定義方法で疑問
記事No7757
投稿日: 2008/06/30(Mon) 10:42
投稿者よねKEN
> > Public な場合は、常にプロパティを使用すべきです。
> > フィールド変数を Public にするのは、ReadOnly な場合だけにしておきましょう。
> →このお作法のメリットが理解できません。(泣)

メリットというよりそうしておかないとデメリットがある、
といった方がよいかもしれません。
先の魔界の仮面弁士さんの投稿にある以下の部分がそれです。

> 使い方が同じだから、どちらでも同じ機能であるかのように見えてしまいますが、
> 後から実装方法を変えるのは、互換性が失われるので避けた方が良いかも知れません。
> たとえば、データバインドなどのように、リフレクションによる実装が行われて
> いる場合には、クラス側にはフィールド変数ではなく、プロパティとしての実装が
> 求められる事もあったりします。

あるクラスを普通に利用する立場から人が見た場合、
フィールドとプロパティは同じ外見を持つので、
まったく同じように見えますし扱えます。
普段は特にそれで問題はありません。

しかし、exeやdllのバイナリデータ上ではフィールドとプロパティは区別されており、
別々のものであるために問題になる場面があります。
その一つはリフレクションですが、この技術は開発環境(VisualStudio)や開発補助ツール、
クラスライブラリなどで使われます。その場合に、プロパティに対して何かを行う
というように開発されることが多いので、フィールドでなく、プロパティで実装して
おいた方が無難ということです。

リフレクションの1例としては、Visual Studioのプロパティウィンドウがわかりやすいでしょうか。
画面にTextBoxを配置したら、プロパティウィンドウにその設定内容が表示され、変更したりできます。
これはSystem.Windows.Forms.dllの中のTextBoxクラスをリフレクションで調査して、
プロパティの一覧を列挙していると思われます。
#例には挙げていますが、このプロパティウィンドウの場合に、
#フィールドだと列挙されなくて期待しない結果になるかどうかは確認していません。

[ツリー表示へ]
タイトルRe^2: [解決] プロパティの定義方法で疑問
記事No7758
投稿日: 2008/06/30(Mon) 13:06
投稿者ダンボ
よねKENさん、どうも有り難うございます。

> その一つはリフレクションですが、この技術は開発環境(VisualStudio)や開発補助ツール、
> クラスライブラリなどで使われます。その場合に、プロパティに対して何かを行う
> というように開発されることが多いので、フィールドでなく、プロパティで実装して
> おいた方が無難ということです。

> 画面にTextBoxを配置したら、プロパティウィンドウにその設定内容が表示され、変更したりできます。
> これはSystem.Windows.Forms.dllの中のTextBoxクラスをリフレクションで調査して、
> プロパティの一覧を列挙していると思われます。

理解しました。このせいかどうかは知りませんが、「プロパティの一覧」には列挙されないくせに
実際は使えるプロパティがありますね。例えばユーザコントロールではDockプロパティがないです。
でもLoadイベントで、
Me.Dock = DockStyle.Fill
とすれば使えます。

[ツリー表示へ]
タイトルRe^3: [解決] プロパティの定義方法で疑問
記事No7759
投稿日: 2008/06/30(Mon) 13:24
投稿者よねKEN
余談です。

> このせいかどうかは知りませんが、「プロパティの一覧」には列挙されないくせに
> 実際は使えるプロパティがありますね。例えばユーザコントロールではDockプロパティがないです。

プロパティ一覧上で表示されていないだけですね。
その辺はプロパティに付与する属性によって制御されています。
詳しいことは以下のあたりで↓。

Visual Studio .NET プロパティ ブラウザによるコンポーネントの本格的な RAD 化
http://www.microsoft.com/japan/msdn/net/general/vsnetpropbrow.aspx
BrowsableAttribute クラス
http://msdn.microsoft.com/ja-jp/library/system.componentmodel.browsableattribute(VS.80).aspx

> でもLoadイベントで、
> Me.Dock = DockStyle.Fill
> とすれば使えます。

各種コントロールはControlクラスを継承しています。
Controlクラスにはかなり様々なプロパティが定義されていますが、
Controlクラスやその派生クラスを継承してより具体的なコントロールを作成する場合、
製作者の意図として、いくつかのプロパティを使って欲しくないような場合があって、
そういう場合にプロパティウィンドウ上では非表示にされているような場合がありますね。

[ツリー表示へ]
タイトルRe^3: [解決] プロパティの定義方法で疑問
記事No7760
投稿日: 2008/06/30(Mon) 13:31
投稿者魔界の仮面弁士
>>> Dimだけは省略必須らしく
実は、必須ではありません。

正確には「省略することが推奨されている」です。
言語仕様上は、Public Dim a As Integer という表現でも許容されますので、
エディタの自動補正をオフにして、Public Dim と書いたとしても、コンパイル可能です。

その逆に「省略しないことが推奨される」例としては、
 If True Then
に対する
 If True
という表記があります(Then は省略可能です)。
この他には、ByVal キーワードなども省略しないことが推奨されていますね。


>>> Public な場合は、常にプロパティを使用すべきです。
>>> フィールド変数を Public にするのは、ReadOnly な場合だけにしておきましょう。
>> →このお作法のメリットが理解できません。(泣)

一般論から言うと、フィールド変数というのは、クラス自身以外から
外部操作される事をあまり想定されていない場合が多いものです。

たとえば、Form2 に TextBox を貼っておき、それを Form1 側から
 Form2.Show()
 Form2.TextBox1 = Nothing
 Form2.TextBox2 = Me.TextBox1
のような処理が行われたとしましょう。
こんな事をされたら、Form2 側が困った事態になりますよね。


それゆえ、フィールド変数はできるだけ公開せず、公開するのであれば、
外から操作できないように ReadOnly にする事が推奨されます。

一方、プロパティとして公開されている場合は、通常それらは、
設計当初から、クラス外部からの操作が考慮されている場合が殆どです。

>>> ・では本当のプロパティのメリットは、
その他には、
 (3) Get/Set それぞれのアクセス レベルを変更する事によって、
  外部からは ReadOnly、内部では Read/Write 可能とすることもできる。
とか。


> 理解しました。このせいかどうかは知りませんが、
>「プロパティの一覧」には列挙されないくせに実際は使えるプロパティがありますね。
それは別の話だったりします。

プロパティには、プロパティ一覧に表示させるか、入力ヒント(IntelliSense)に
表示させるかどうかを制御するための属性を付けることができるのです。

その逆に、実際には存在しないのに、プロパティグリッドには表示される物もあります。
たとえば、コントロールの GenerateMember プロパティや Modifiers プロパティなどが
それにあたります。(これらのプロパティは、デザイナによって提供されます)

[ツリー表示へ]