C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

コンストラクタのアクセス可否

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■86313 / inTopicNo.1)  コンストラクタのアクセス可否
  
□投稿者/ ユージ (1回)-(2018/01/17(Wed) 12:38:03)

分類:[VB.NET/VB2005 以降] 

2018/01/17(Wed) 12:51:47 編集(投稿者)

開発言語:VB2013

クラスAのメンバに、クラスBの変数があるものとします。
ただ、クラスBの実体はクラスA内の処理でのみ生成できるようにしたいのです。
つまり、外部からのクラスBの参照はできるようにしたいのですが、
クラスBのコンストラクタはクラスAの外部からは呼び出せないようにしたいのです。

このようなことは可能でしょうか?
また、クラスAをDLL化すれば可能でしょうか?
(クラスBのコンストラクタのアクセス修飾子をFriendにする等)
引用返信 編集キー/
■86314 / inTopicNo.2)  Re[1]: コンストラクタのアクセス可否
□投稿者/ 魔界の仮面弁士 (1537回)-(2018/01/17(Wed) 13:30:43)
No86313 (ユージ さん) に返信
> クラスBの実体はクラスA内の処理でのみ生成できるようにしたいのです。

こういう方法は如何でしょう。

Public Class Form1
  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim a As ClassA = ClassA.Create()
    Dim b As ClassB = a.Child
    'Do Anything
  End Sub
End Class

Public NotInheritable Class ClassA
  Private Sub New()
  End Sub
  Public ReadOnly Property Child As ClassB
  Public Shared Function Create() As ClassA
    Dim owner As New ClassA()
    owner._Child = New ClassB(owner)
    Return owner
  End Function
End Class

Public Class ClassB
  Public Sub New(owner As ClassA)
    If owner Is Nothing Then
      Throw New ArgumentNullException("owner")
    End If
  End Sub
End Class
引用返信 編集キー/
■86316 / inTopicNo.3)  Re[1]: コンストラクタのアクセス可否
□投稿者/ 魔界の仮面弁士 (1538回)-(2018/01/17(Wed) 14:08:34)
No86313 (ユージ さん) に返信
> また、クラスAをDLL化すれば可能でしょうか?
> (クラスBのコンストラクタのアクセス修飾子をFriendにする等)

こっちの回答を忘れていました。


『ConsoleApplication1』
Module Module1
 Public Sub Main()
  'エラー BC30517 'New' にアクセスできないため、オーバーロードの解決に失敗しました。
  'Dim b As New ClassB()

  Dim a As New ClassA()
  Dim b As ClassB = a.Child

 End Sub
End Module


『SampleLibrary.dll』
Public NotInheritable Class ClassA
  Public Child As ClassB
  Public Sub New()
   Child = New ClassB()
  End Sub
End Class
Public Class ClassB
  Friend Sub New()
  End Sub
End Class
引用返信 編集キー/
■86317 / inTopicNo.4)  Re[2]: コンストラクタのアクセス可否
□投稿者/ ユージ (2回)-(2018/01/17(Wed) 17:54:29)
魔界の仮面弁士様、ご回答ありがとうございました。
ちょっと試してみます。

ところで、DLL化しない方法で質問があります。

Public NotInheritable Class ClassA 内の
Public ReadOnly Property Child As ClassB の
「ReadOnly」キーワードは、ClassAの外で参照する場合
ReadOnlyという意味なのでしょうか?
(ClassA内であれば別のClassBの実体に置き換え可能?)

どうもReadOnlyの適用範囲がうまく理解できいないようで、恐縮です。
引用返信 編集キー/
■86319 / inTopicNo.5)  Re[3]: コンストラクタのアクセス可否
□投稿者/ 魔界の仮面弁士 (1539回)-(2018/01/17(Wed) 23:33:47)
No86317 (ユージ さん) に返信
> ところで、DLL化しない方法で質問があります。
おっとっと…そういえば、DLL 化した方に ReadOnly をつけ忘れていますね。
そのままだとマズいので、どちらも ReadOnly にしておいてください。


> Public NotInheritable Class ClassA 内の
> Public ReadOnly Property Child As ClassB の
> 「ReadOnly」キーワードは、ClassAの外で参照する場合
> ReadOnlyという意味なのでしょうか?

外だけでなく中でも読み取り専用です。

まずは『ReadOnly フィールド』の仕様から先に説明しますが、
 Public ReadOnly Test As Integer
とした場合、ClassA の外部はもちろん、ClassA 自身にとっても ReadOnly になります。

 Private Sub Method()
  'エラー BC30064 'ReadOnly' 変数を代入式のターゲットにすることはできません。
  'Me.Test = 123
 End Sub

ReadOnly なフィールド変数に値をセットできるのは、初期化シーケンスに限定されます。
すなわち、
 Public ReadOnly Test As Integer = 123
のように初期値として設定しておくか、もしくはコンストラクタの段階でのみ値をセットできます。

これがインスタンス フィールド ではなく、Shared ReadOnly な共有フィールドだった場合は、
共有コンストラクタ Shared Sub New() 内での初期化になります。



さて、ここまでは「ReadOnly フィールド」の話でしたが、
今度は本題となる、 No86314 で使われている「ReadOnly プロパティ」の話。


といっても、プロパティであれフィールドであれ、ReadOnly キーワード付きである以上、
内部からでも外部からでも、直接代入ができないという点は変わりません。

しかし、読み取り専用であるとは言っても、何かしらの値はセットしておかねばなりません。
ただ、その手段がフィールドとプロパティでは異なっていますので、ここでは分けて説明しています。


まず先述のコードにある

 Public ReadOnly Property Child As ClassB

というのは、「自動実装プロパティ」(Auto-Implemented Properties) による
糖衣構文となります。そしてこれは実際には

 Public ReadOnly Property Child() As ClassB
  Get
   Return _Child
  End Get
 End If
 Private _Child As ClassB

と完全に等価なコードを意味します。ここでは、Private 変数が用意されていることに着目して下さい。


それゆえ No86314 で示したように、「Child」ではなく「_Child」へアクセスすることで、
プロパティが返すべき値をセットすることができるようになっているというわけです。

> Dim owner As New ClassA()
> owner._Child = New ClassB(owner)

この「_Child」変数は Private なので、外部からはアクセスできません。


ちなみに、自動実装プロパティで生成される「_プロパティ名」な Private 変数のことを
そのプロパティの「バッキング フィールド」(Backing Fields)と言います。
https://msdn.microsoft.com/ja-jp/library/dd293589%28vs.120%29.aspx



それと、自動実装プロパティは VB2010 から追加された機能なので、それ以前のバージョンでは
Property 〜 End Property までのブロック表記で記述するようにしてください。
また、ReadOnly な自動実装プロパティを実装するには、VB2015 以降のバージョンが必要です。



> どうもReadOnlyの適用範囲がうまく理解できいないようで、恐縮です。
今回のケースにおいて、何故 ReadOnly にする必要があるかというと、
ReadOnly でないフィールドやプロパティは、ClassA の外部から
  Dim b As ClassB = a.Child
  y.Child = b
  x.Child = Nothing
のようにして、インスタンスを差し替えられてしまうからです。
ReadOnly なら、外部から代入される心配は無いですね。


あるいは ReadOnly メンバーではなく、メソッドの戻り値として
  Dim b As ClassB = x.GetChild()
のように実装する手法もありますね。
実行されるたびに、新しい ClassB インスタンスを用意する必要が
ある場合は、プロパティではなくメソッドとして実装するのが良いでしょう。
引用返信 編集キー/
■86324 / inTopicNo.6)  Re[4]: コンストラクタのアクセス可否
□投稿者/ ユージ (3回)-(2018/01/18(Thu) 11:31:40)
魔界の仮面弁士様、ご回答ありがとうございました。
いつもProperty 〜 End Propertyに慣れていて
場合によってはPropertyブロック内に処理を入れる場合もあり、
自動実装プロパティは今まで使ったことがありませんでした。
加えて、「_プロパティ名」のアンダースコアを見落としていました。
ようやく理解できました。

引き続き、ご提示のソースで勉強します。

引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ