1

Suppose I have the following class:

Public Class lbMenu

    Inherits Form

    ...

    Public Sub AddItem(header As String)
        Dim item As New lbMenuItem()
        item.Owner = Me
        item.Header = header
        Controls.Add(item)
    End Sub

    ...

End Class

and also the following class:

Public Class lbMenuItem

    Inherits Control

    Private _Owner As lbMenu
    Public Property Owner As lbMenu
        Get
            Return _Owner
        End Get
        Set(value As lbMenu)
            _Owner = value
        End Set
    End Property

    Private _Header As String
    Public Property Header As String
        Get
            Return _Header
        End Get
        Set(value As String)
            _Header = value
        End Set
    End Property

    ...

End Class

As you can see, I access the Owner property of lbMenuItem from the class lbMenu.

What I want is that nobody else can access the Owner property, or maybe just to read the value of the property. I think there is no way to do that but maybe there is a solution to reach a similar situation.

Any suggestions?


Edit:

I already considered passing the owner as a parameter in the constructor, but I want that anyone can access the lbMenuItem class. Anyone can create a new instance of the class, read and write many properties, etc. The only thing I don't want is that someone can write the Owner property. Someone can create a new instance of the class without having to pass an ownerMenu parameter to the New method (he can't know what ownerMenu is for). For the same reason, lbMenuItem can't be a nested class of lbMenu. I'm trying to get the same result as with ContextMenuStrip and ToolStripMenuItem. ToolStripMenuItem has an Owner property (which in this case has read/write access) and an OwnerItem which is read-only. So, is there a way to make the Owner property read-only but writable from the lbMenu class?

lucasugar
  • 13
  • 3
  • 1
    It could be part of the New while having the property readonly. If the write part of the property could be friend, depends on the need. – the_lotus Apr 05 '18 at 17:34
  • You can protect that property with the [Friend](https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/access-levels) keyword but it is not clear if this is enough. It depends on how you have structured your program – Steve Apr 05 '18 at 17:35
  • Does `lbMenu` need to access `lbMenuItem.Owner` after an instance of `lbMenuItem` is created? – Andrew Morton Apr 05 '18 at 17:36
  • Yes, in some cases lbMenu needs to access the lbMenuItem.Owner property. – lucasugar Apr 05 '18 at 20:53
  • I just edited my answer to address the new points you added. – 41686d6564 stands w. Palestine Apr 05 '18 at 22:36
  • Just curious why you need such level of protection? If I am developer and having access to the class, and feel that I need to set `Owner` I will create setter for that even you spend time for defensing against it. Having constructor and readonly property will be tell me that owner should be set only through constructor. – Fabio Apr 06 '18 at 06:15
  • I can't believe!!! I always misundertood the meaning of the keyword `Friend`! (well, I never coded a dll before). That's exactly what I **need**. Thank you all very much! – lucasugar Apr 06 '18 at 19:21

1 Answers1

0

You could just have the Owner property private or read-only if you want to allow reading its value and set it in the constructor.

Edit:

Someone can create a new instance of the class without having to pass an ownerMenu parameter to the New method

Well, you can have two constructors, one that accepts a lbMenu parameter, and one without. So, your code would look something like this:

Public Class lbMenu

    Public Sub AddItem(header As String)
        Dim item As New lbMenuItem(Me)
        item.Header = header
        Controls.Add(item)
    End Sub

End Class

Public Class lbMenuItem

    ' Use this instead if you don't want the property to be accessible at all.
    'Private Property Owner As lbMenu

    Public ReadOnly Property Owner As lbMenu
    Public Property Header As String

    ' Allow creating an instance of the class without having to pass/set the owner.
    Public Sub New()
    End Sub

    Public Sub New(ownerMenu As lbMenu)
        Owner = ownerMenu
    End Sub

End Class

One last recommendation:

Based on the names of your classes, you might consider having a parent/child relationship between them (i.e., the lbMenuItem class would be a nested class within lbMenu). This will give you the advantage of being able to access the private members of lbMenu from a lbMenuItem instance.

Hope that helps.


Addressing the new points in your edit:

ToolStripMenuItem has an Owner property ... and an OwnerItem which is read-only.

That's exactly what I proposed (i.e., to use a read-only property). Note that the OwnerItem property isn't exposed as writable to any other class.

So, is there a way to make the Owner property read-only but writable from the lbMenu class?

No, that's not possible. A read-only property is read-only, period. You can't expose its setter to a specific class. You can, however, limit the accessibility to its setter by using the keywords Friend, Private, or Protected:

  • Friend Set --> will make the setter accessible (make the property writable) inside the current project and read-only outside the project.
  • Private Set --> will make the setter accessible from the child classes.
  • Protected Set --> will make the setter accessible from the derived classes.

Take a look at this question to get a better idea on how to limit the accessibility of a property setter. It's about C#, but the concept is the same.

lucasugar
  • 13
  • 3
  • @lucasugar please only use the 'edit' link to improve answers/questions, not to reply. If you'd like to address something in an answer, you can either add a comment or edit your question and add the new information. I already took care of that for you. – 41686d6564 stands w. Palestine Apr 05 '18 at 21:41
  • Yes, you're right. The `Friend` keyword is what I need. Thank you very much. – lucasugar Apr 06 '18 at 19:31
  • @lucasugar Glad I was able to help. If the answer solved your problem, you might consider [accepting it](https://stackoverflow.com/help/accepted-answer). If there's still something not clear, please let me know. – 41686d6564 stands w. Palestine Apr 08 '18 at 11:24