- PR -

特定のクラスのみ別クラスのプロパティへのアクセスを許可したい

投稿者投稿内容
ガルマ・ザビ
ベテラン
会議室デビュー日: 2007/06/07
投稿数: 55
お住まい・勤務地: ジオン公国
投稿日時: 2008-02-22 16:27
mName をプロパティ化し、Get、Setを設ける。

PersonalクラスにIPersonalインターフェースみたいなのを継承させ、
mNameのプロパティのゲッターだけ公開。

Formからは、IPersonalインターフェース経由で触らせる、、、とか。

でも、やっぱり、じゃんぬねっとさんのやり方がいいんですけどね、、。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2008-02-22 17:38
引用:

ガルマ・ザビさんの書き込み (2008-02-22 16:27) より:
mName をプロパティ化し、Get、Setを設ける。

PersonalクラスにIPersonalインターフェースみたいなのを継承させ、
mNameのプロパティのゲッターだけ公開。

Formからは、IPersonalインターフェース経由で触らせる、、、とか。



これ実験してみましたが、インターフェースでReadonlyのプロパティを宣言した場合、
具象クラスでは、Read/Writeなプロパティにはできないっぽいです。
(Visual Studio 2005 VB)
# 何か設定でもあるのかな?

すなわち
コード:
Public Interface IPerson
    Readonly Property Name As String
End Interface

Public Class Person
Inherits IPerson
...
    Public Property Name As String
        Get ....
        Set ....
    End Property
End Class


上記のコードではコンパイルエラーになりました。

泥臭いですが、
コード:
Public Class Person
    Private _Name As String
    
    Public Overloads Sub New() 
    End Sub
    
    Public Overloads Sub New(ImmutablePerson P)
        Me.Name = P.Name
    End Sub
    
    Public Property Name As String
        Get ....
        Set ....
    End Property
    
    Public ReadOnly Property Person As ImmutablePerson
        Get
            Return New ImmutablePerson(Me)
        End Get
    End Property
End Class

Public Class ImmutablePerson
    Private _P As Person
    
    Public Sub New(Byref P As Person)
        _P = P
    End Sub
    
    Public Property Name As String
        Get 
            Return _P.Name
        End Get
    End Property
End Class

Dim P As Person = New Person()
P.Name = "AAA" 'セットできる

Dim IP As ImmutablePerson = P.Person
P.Name = "BBB" 'セットできないため、コンパイルエラー


上記のようなコードしか思いつきませんでした。ふいんき(←なぜか変換できない)的には一郎さんに近いですね。

Companyクラスでは、リストの宣言を
Private mEmployees As New List(Of Personal)
ではなく
Private mEmployees As New List(Of ImmutablePersonal)
にすれば、他からどころか自身でも変更できなく出来ます。

変更したい場合は
コード:
New Person(ImmutablePersonのインスタンス)


のように、新しいインスタンスを作成し、元の値と置き換えると。


まりも
ベテラン
会議室デビュー日: 2006/08/19
投稿数: 77
投稿日時: 2008-02-22 17:53
似たようなことができるように考えてみましたが。

案1.NameプロパティにPrivateなSetを定義して、CompanyクラスをPersonalクラスの内部クラスにする。

これだとクラスが内部クラスになってしまって、影響が大き過ぎる可能性が高いので、

案2.Companyクラス内にNameに対するアクセサっぽいメソッドを作って、それを利用する。

コード:
    Public Sub New()
        Dim personal As New Personal()
        Console.WriteLine(personal.Name)
        SetName(personal, "IT太郎")
        mEmployees.Add(personal)
    End Sub

    Private Sub SetName(ByVal personal As Personal, ByVal name As String)
        personal.GetType() _
            .GetField("mName", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance) _
            .SetValue(personal, name)
    End Sub



私がやるとしたらこんな感じでしょうか。
インターフェース案のほうがいいようなきもしてきましたが。
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-02-22 18:04
コード:

Interface IPerson
WriteOnly Property Name() As String
End Interface

Public Class Person
Implements IPerson

Private _Name As String

Public ReadOnly Property Name() As String
Get
Return _Name
End Get
End Property

Protected WriteOnly Property Name1() As String Implements IPerson.Name
Set(ByVal value As String)
_Name = value
End Set
End Property
End Class



セットするときは
CType(Personインスタンス, IPerson).Name = "お名前"

こんな感じで無理やり隠蔽。

[追加]
上記PersonクラスとIPersonインターフェースをCompanyクラスの内部で定義し
IPersonはProtected。PersonはPublicとすることで
Companyクラス以外からは設定出来ない作りになるかな。

どのみち、インターフェース経由しないと設定できない点は煩わしいですが。

やはり別アセンブ・・・(ぃぇ、なんでもないです。

[ メッセージ編集済み 編集者: くまっち 編集日時 2008-02-22 18:37 ]
ガルマ・ザビ
ベテラン
会議室デビュー日: 2007/06/07
投稿数: 55
お住まい・勤務地: ジオン公国
投稿日時: 2008-02-22 18:41
引用:

かずくんさんの書き込み (2008-02-22 17:38) より:

これ実験してみましたが、インターフェースでReadonlyのプロパティを宣言した場合、
具象クラスでは、Read/Writeなプロパティにはできないっぽいです。
(Visual Studio 2005 VB)
# 何か設定でもあるのかな?




C#だといけたので、VBもいけるかと思い書き込んでしまったのですが、
自分でもVBで書いてみたところ、コンパイルエラーが出ました。

ご迷惑をおかけしました。
ani
常連さん
会議室デビュー日: 2007/05/17
投稿数: 44
投稿日時: 2008-02-22 22:42
みなさま、たくさんのそして親切なレスありがとうございます。
大変感謝いたしております。
(まとめてのお礼になり申し訳ありません。)

あれからいろいろと試しまして、以下のようなコードを書いてみました。
コード:
'個人情報クラス
Public Class Personal

    Protected mName As String
    Protected mAddress As String
    Protected mAge As Integer

    Public ReadOnly Property Name() As String
        Get
            Return Me.mName
        End Get
    End Property

End Class

'個人情報クラス
Public Class Company

    Private Class PersonalInherits : Inherits Personal
        Public Property _Name() As String
            Get
                Return MyBase.mName
            End Get
            Set(ByVal value As String)
                MyBase.mName = value
            End Set
        End Property
    End Class

    Private mCompanyName As String
    Private mEmployees As New List(Of Personal)

    Public Sub New()
        Dim personal As New PersonalInherits()
        Console.WriteLine(personal.Name)
        personal._Name = "IT太郎" 'OK
        mEmployees.Add(DirectCast(personal, Personal))
    End Sub

End Class

'フォームクラス
Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim personal As New Personal()
        Console.WriteLine(personal.Name)
        'personal.Name = "IT太郎" 'エラー
    End Sub

End Class


何となく動いているようなのですが、問題は多々あると思います。
(基本的に継承の使い方が間違っているとは思います。)

インターフェースについてまだ理解ができていないため、みなさまにご教示いただいたコードはまだ試していません。
申し訳ありません。
よく理解して試してみたいと思います。

また「読み取り専用」の解釈のご指摘、ありがとうございます。
やりたいことは unibon さんがおっしゃった「操作間違いを防ぐ」ことなのですが、
アセンブリが同じであればクラスを使用する側で注意してもらう方が良さそうですね。
私も本当は別アセンブリにしたいです。。。

スキルアップ/キャリアアップ(JOB@IT)