Results 1 to 11 of 11

Thread: Noob help with "nesting" classes!

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Jan 2022
    Posts
    26

    Noob help with "nesting" classes!

    Hi All,

    I have a strong VBA background and am trying to break into the depths of .NET! Bear with me as I struggle to solve this issue!

    I am trying to nest classes. Any child (or shall we... grandchild) class must be able to access any of it's parents (.... or grandparents) INSTANCE's properties.
    A child/grandchild is useless without it's parents, and therefore should not be allowed to be called discretely.

    I know this is asked a lot and i've sifted through the interwebs, just seems like there are many ways to skin this cat and i'm not sure what is the best for my scenario....

    Here is what I have as a 'mock up'.

    Code:
    Class App
    
            Public ReadOnly Property AppName As String
                Get
                    AppName = "Test Application"
                End Get
            End Property
    
            Public Class Database
                Dim DatabaseName As String = "Test Application Database"
    
                Public Sub PrintAppName()
                    Console.WriteLine("APP NAME IS:  " & AppName)
                End Sub
    
    
                Public Class Functions
                    Public Shared Sub PrintDatabaseName()
                        Console.WriteLine("DB NAME IS: " & DatabaseName)
                    End Sub
                End Class
            End Class
        End Class
    
    
        Sub Main()
            Dim a As New App
    
            'want to use like this! 
            a.Database.PrintAppName()
            a.Database.Functions.PrintDatabaseName()
    
        End Sub


    Thank you for your time!

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    Re: Noob help with "nesting" classes!

    You seem confused about the difference between a type and an object. The fact that a class is declared inside another class says nothing about objects of those two types. You can create an instance of the outer class but that doesn't mean that an instance of the inner class automatically exists and vice versa.

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    Re: Noob help with "nesting" classes!

    As examples, the ListViewSubItem class is nested inside the ListViewItem class but you can still create an instance of the former without creating an instance of the latter. You can't really use it in any meaningful way but there's no specific relationship between their existence. Conversely, the DataRow class is not nested within the DataTable class, yet the only way to create a DataRow is via a DataTable. An object accessing properties of another object requires a relationship between the objects, not just between the types.

  4. #4

    Thread Starter
    Junior Member
    Join Date
    Jan 2022
    Posts
    26

    Re: Noob help with "nesting" classes!

    Hi,

    Thanks for your reply. I follow to a degree. But I am not following in full.

    So, if this "requires a relationship between the objects", could you explain how to ties these classes together?

    Below i've attempted to solve this by creating an instance of the child object at the constructor of the parent class.

    But the code below does not work. If someone could offer a code example of how 'nesting' classes is done, then I think it would help me tie the pieces together.

    Thanks


    Edit: To further the confusion I have, this post does a wonderful job explaining my exact mindset:
    http://https://stackoverflow.com/que...-another-class

    Code:
    Class App
    
            Public ReadOnly Property AppName As String
                Get
                    AppName = "Test Application"
                End Get
            End Property
    
            Public Sub New()
                'initilize a database object
                Dim vDatabase As New Database
            End Sub
    
            Public ReadOnly Property GetDatabase As Database
                Get
                    GetDatabase = vDatabase
                End Get
            End Property
    
            'child class:
            Public Class Database
                Dim DatabaseName As String = "Test Application Database"
    
                Public Sub PrintAppName()
                    Console.WriteLine("APP NAME IS:  " & AppName)
                End Sub
    
            End Class
        End Class
    
    
        Sub Main()
            Dim a As New App
    
            a.GetDatabase.PrintAppName()
    
        End Sub
    
    
    
    End Module
    Last edited by BitFlipper88; Nov 30th, 2022 at 10:04 PM.

  5. #5
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    Re: Noob help with "nesting" classes!

    Crash course time. OOP is intended to mimic the way objects work in the real world, so you just have to look at real-world objects and how we deal with them to get a decent understanding of OOP.

    When we look around at physical objects, we classify them, e.g. that's a building, that's a car, that's a tree, that's an animal. We all understand what those things are because we understand the description of what an object of that type has and what it does. It is from this classification that we derive the word "class" used in OOP. A class is a description of what a type of thing has and what it does. As in the real world though, we need instances of a type in order to actually do anything. You know what a car is, what it has and what it does, but you need a car object to actually drive anywhere. Every car has a colour but each car can have a different colour. All cars have doors but each car can have a different number of doors. Etc, etc. It's the same in the real world and in OOP.

    You ask how to nest classes and the answer is to declare one inside the other. That's it, that's all. E.g.
    vb.net Code:
    1. Public Class Parent
    2.  
    3.     Public Class Child
    4.  
    5.     End Class
    6.  
    7. End Class
    That's all there is to nested classes. If your actual problem is how to access the members of a Parent object from a Child object then that has nothing to do with nesting. In order for a Child object to access the properties of a Parent object, it must have a reference to a Parent object. That would be done the same way whether or not one class is nested within the other. The Child class would have to have a field/property of type Parent that you assign a Parent object to. Any Child object can then access the members of the Parent object assigned to that field/property. E.g.
    vb.net Code:
    1. Public Class Parent
    2.  
    3.     Public Property Text As String
    4.  
    5. End Class
    6.  
    7. Public Class Child
    8.  
    9.     Public Property Parent As Parent
    10.  
    11.     Public Sub SetParentText(text As String)
    12.         If Parent IsNot Nothing Then
    13.             Parent.Text = text
    14.         End If
    15.     End Sub
    16.  
    17. End Class
    vb.net Code:
    1. Dim p As New Parent
    2. Dim c As New Child
    3.  
    4. c.Parent = p
    5. c.SetParentText("Hello World")
    You can do that same thing whether or not the classes are nested. The details of how you maintain the relationship could vary, so it's up to you to make it work the way you want. For instance, you might implement it such that if a Parent refers to a specific Child then that Child also refers to that specific Parent and no other Child refers to it and vice versa. E.g.
    vb.net Code:
    1. Public Class Parent
    2.  
    3.     Private _child As Child
    4.  
    5.     Public Property Child As Child
    6.         Get
    7.             Return _child
    8.         End Get
    9.         Set(value As Child)
    10.             If value Is Nothing Then
    11.                 If _child IsNot Nothing Then
    12.                     Dim oldChild = _child
    13.  
    14.                     _child = Nothing
    15.                     oldChild.Parent = Nothing
    16.                 End If
    17.             ElseIf value IsNot _child Then
    18.                 Dim oldChild = _child
    19.  
    20.                 _child = Nothing
    21.                 oldChild.Parent = Nothing
    22.  
    23.                 _child = value
    24.                 _child.Parent = Me
    25.             End If
    26.         End Set
    27.     End Property
    28.  
    29. End Class
    30.  
    31. Public Class Child
    32.  
    33.     Private _parent As Parent
    34.  
    35.     Public Property Parent As Parent
    36.         Get
    37.             Return _parent
    38.         End Get
    39.         Set(value As Parent)
    40.             If value Is Nothing Then
    41.                 If _parent IsNot Nothing Then
    42.                     Dim oldParent = _parent
    43.  
    44.                     _parent = Nothing
    45.                     oldParent.Child = Nothing
    46.                 End If
    47.             ElseIf value IsNot _parent Then
    48.                 Dim oldParent = _parent
    49.  
    50.                 _parent = Nothing
    51.                 oldParent.Child = Nothing
    52.  
    53.                 _parent = value
    54.                 _parent.Child = Me
    55.             End If
    56.         End Set
    57.     End Property
    58.  
    59. End Class
    I haven't tested that but I believe that it should do the job.

    Again, if what you actually want is for a Child to not be able to be created except via a Parent then nesting classes won't do that. You would have to do what I already told you and define those classes in their own assembly (library) without any public means to create a Child directly. E.g.
    vb.net Code:
    1. Public Class Parent
    2.  
    3.     Public Function NewChild() As Child
    4.         Return New Child(Me)
    5.     End Function
    6.  
    7. End Class
    8.  
    9. Public Class Child
    10.  
    11.     Public ReadOnly Property Parent As Parent
    12.  
    13.     Friend Sub New(parent As Parent)
    14.         Me.Parent = parent
    15.     End Sub
    16.  
    17. End Class
    Because they are in the same assembly, the Parent class can access the Child class constructor declared Friend but any code outside that assembly cannot, thus the Public NewChild method is the only way to create a new Child object and it will automatically have a reference to the Parent that created it. That's basically how the DataTable and DataRow classes work.

  6. #6

    Thread Starter
    Junior Member
    Join Date
    Jan 2022
    Posts
    26

    Re: Noob help with "nesting" classes!

    Update:

    So I played around some more and was able to essentially solve my problem.

    Code:
    Module Module4
        'AN EXAMPLE OF NESTED CLASSES....
        Class MainClass
    
            Private Shared MainVar As String = "Main!"  'MUST BE SHARED FOR CHILD CLASS TO ACCESS
    
            Public Child As ChildClass
            Sub New()
                Child = New ChildClass
            End Sub
    
            Class ChildClass
    
                Public Sub DoSomething()
                    MsgBox("Hello " & MainVar)  'mainvar must be 'SHARED'
                End Sub
    
                Public Sub DoSomething2()
                    MsgBox("Do Something 2 " & MainVar)
    
                End Sub
    
            End Class
    
        End Class
    
    
    
        Sub Main()
            Dim m As New MainClass
            Dim c As New MainClass.ChildClass
    
            c.DoSomething2()
    
            m.Child.DoSomething()
        End Sub
    
    
    
    End Module

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    Re: Noob help with "nesting" classes!

    Is that a solution though? A Sahred member is one that belongs to the class, rather than each instance of the class, so there will only be one MainVar value, no matter how many MainClass instances you create. Maybe you only intend to create one instance but this is still a bit of a hack.

    Also, why are you declaring MainClass inside Module1? Even if you're going to ignore advice and nest one class inside another, there's no justification for nesting the outer class inside a module.

  8. #8
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,044

    Re: Noob help with "nesting" classes!

    The module might be a holdover from VBA. I think everything was in modules in VBA, though it's been many years since I've worked in VBA.

    A module in .NET is essentially a class with all Shared members. It's a fig leaf added to make VB.NET act more like VB6, which was based on VBA syntax, as well as earlier versions of VB. Modules have their place in VB.NET, but they are fairly rare. I use them if I have global variables. Since global variables are, themselves, fairly problematic, they are usually not the right way to go, so I rarely use modules, and never more than one.

    A class should be in it's own file, or files. If you want a nested class, it might be nicest to put it in a different file. That might be going a bit far, but a single class can be spread across multiple files, as you can have the class in one file, then the other files would have a Partial Class in them (which are part of the same class):

    In one file:
    Code:
    Public MyClass
    
    End Class
    In a second file
    Code:
    Partial Class MyClass
     Public Class MyInnerClass
      
     End Class
    End Class
    All of this would still allow a person to create an instance of the inner class, so there's little reason to nest them if this is all you are doing. There are a couple ways to ensure that inner classes can't be created when they shouldn't be. One thing you could do is put the whole thing into a class library. They you can declare the outer class as Public and the inner class as Friend. Any project referencing the dll can create an instance of the outer class, but they won't even know about the inner class, since things declared Friend are not exposed outside the assembly.

    I'd also say that you almost certainly don't want to be using Shared, there. It might seem to work, but it almost certainly doesn't do what you want, and you'll end up regretting it.
    My usual boring signature: Nothing

  9. #9

    Thread Starter
    Junior Member
    Join Date
    Jan 2022
    Posts
    26

    Re: Noob help with "nesting" classes!

    Hello all,

    I've spent a considerable amount of time getting my feet wet in VB.net. Lots to learn (so many modifiers, etc).

    So, I am currently using the approach where the classes are built un-nested. And the constructor sets their references. Indeed I see the flaw with my "solution" earlier. Totally incorrect. My point for "nesting classes" is that I want a clean hierarchical design. Much like you see in OOP and especially VBA. Similar to that of a code library / namespace. I am considering having the children be hidden from intellisense, unless accessed through the parent. But this is not a huge requirement. In that case, I assume the classes would have to be nested.

    Ultimately I have learned a lot about accessibility with this little project.

    I had a bit of cognitive dissonance here because VBA tainted me with not having constructors. And therefore, setting references to a parent/child becomes hideous code at the caller level.

    As for the comment on the Module being inserted.... I am testing the class with Main() in the same file. Again, I know nothing about how to actually use Visual Studio other than what I know from VBA

    jmcilhinney, thanks for your code provisions. Very useful.

    Shaggy Hiker, you bring up a good point about VBA and the whole 'shared' thing. I do understand that Shared is NOT a solution for accessibility between child/parent classes like I suggested.

    I have not explored partial classes yet at all and not sure what that even means!

    Thanks all

  10. #10
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,044

    Re: Noob help with "nesting" classes!

    Partial classes was introduced in VS2005. Prior to that time EVERY part of a class had to be in a single file. That may not sound too bad for you, but if you take a close look at a form, you'll see why it was painful. Depending on selections you have made, you may or may not be seeing the .designer.vb file associated with every form. Forms in .NET are just plain ol' .NET code. You could write it all yourself...if you were a masochist. As it is, it's tucked away in the .designer.vb file. Take a look at one (you may have to hit the Show All Files icon in Solution Explorer, if the file isn't visible). There's a lot of fairly dull code in there, but the key point is that for any reasonably sizable form, there really is a LOT of code there. Prior to partial classes, ALL of that code was stuffed into just the one code file along with all your event handlers and anything else you wrote. It would be put into a Region block at the top of the file, along with a comment suggesting that you not mess with it, but it was all there. Total nuisance.

    So, all that a partial class is, is a means to spread the code associated with a class definition across multiple files. By far, the most common use of this is so that all the designer generated code can be put off in the .designer.vb file so you don't have to see it all the time, and are less likely to mess things up by altering it, but that's all it is doing. You can use partial classes yourself, as I mentioned. It's just telling the compiler, "this code here is actually part of that other class that you already know about." That is rarely done, because a class so large that it sprawls across multiple files is usually a bad idea.

    I'm using that because I have a class library (which is just a dll) where there are some classes that make no sense outside of a different class. I certainly could have moved them outside of the container class. They can only be created in that dll, so it's not like anybody would try to make an instance of one of them on their own. They won't even know about them. However, I wanted to make it rather explicitly clear in the code that the class has no meaning outside of the container, so I made them classes in the container. It's the only time I've done that, and as I said, I didn't need to. It really gained nothing at all, aside from making it abundantly clear what my intent was.
    My usual boring signature: Nothing

  11. #11
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,044

    Re: Noob help with "nesting" classes!

    One other point is that Main() is rarely used, these days, though there are times when it is the right way to go. From what you've said, you sound like you have found one of those cases. Most programs use a startup form. There is always an entry point to a program, and that entry point, by convention, is a Sub Main(), but it's usually hidden. It's not much of a point.
    My usual boring signature: Nothing

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width