4

I come from the VBA world where options to breakdown your code into classes, namespaces, and modules is limited. Now I just landed in a world where the options are many, and I feel lost.

I would like to know what is the purpose of declaring a Class within another Class? (see example below)

Class FirstClass
    Public OnePropertyInside As String
    Class SecondClass
        Public AnotherProperty As String
    End Class
End Class

If I create a new instance of FirstClass (say myFirstClass), SecondClass is not instantiated. Even more bizzare (to me at least), is that intelissense offers me myFirstClass.SecondClass. Obviously, because the class is not instantiated, I cannot access any of its members.


So, is that usefull only if the SecondClass contains shared members? To try answering that question I added a shared member within SecondClass:

Class FirstClass
    Public OnePropertyInside As String
    Class SecondClass
        Public AnotherProperty As String
        Public Shared SharedProperty As String
    End Class
End Class

I ran a few tests which brought secondary questions (see comments in code)

Sub Main()       

    Dim myFirstClass As New FirstClass
    'Works as expected
    Console.WriteLine(myFirstClass.OneProperty)

    'What is the difference between the two lines below?
    Console.WriteLine(myFirstClass.SecondClass.SharedProperty)
    Console.WriteLine(FirstClass.SecondClass.SharedProperty)

    'This line cannot be compiled, this demonstrates SecondClass is not instantiated when FirstClass is.
    Console.WriteLine(myFirstClass.SecondClass.AnotherProperty)

    Dim mySecondClass As New FirstClass.SecondClass
    'Works as expected, but I feel this hierarchy should better be dealt with through a namespace statement?
    Console.WriteLine(mySecondClass.AnotherProperty)

End Sub
Ama
  • 1,373
  • 10
  • 24

3 Answers3

5

You can think of it as if the inner most class is a helper class of sorts. It may not even need to be used at all. Nesting the inner class(or simply nested class) inside the outer class gives you access to all of the members of the outer one. You can even access the private members inside that initial outer class.

Edit: For clarification, I mean to say that the the inner can access the private members of the outer, not the other way around.

AMDarwech
  • 71
  • 1
  • 7
  • 2
    That's not true. The outer class cannot access the private members of the nested class. – Steven Doggart Feb 07 '19 at 16:09
  • @StevenDoggart maybe my response is is written in such a way to confuse, I've edited accordingly, its' meant to convey that the inner can access the outer's private methods. – AMDarwech Feb 07 '19 at 16:15
  • 2
    I was getting confused. So this is just an expected behaviour, right? The 'mother' class declares private members, which can only be accessed from within th Class block. Since the nested class is part of the 'mother' class block, it can access the aforementionned private members? – Ama Feb 07 '19 at 16:17
  • @Ama yes, exactly! – AMDarwech Feb 07 '19 at 16:18
3

You usually do this because you want to restrict the scope of the nested class.

So, if you only need to use this class from within the "parent" class (in terms of scope), then its usually a good idea to define it as a nested class.

If you might might need to use the class outside of its assembly, then it is better to define it as a completely separate class (in its own file), and then define your relationship accordingly. You will need to instantiate one within the other (this is the same whether its seperate or nested - so its location is largely irrelevant for that point).

Robert Perry
  • 1,906
  • 1
  • 14
  • 14
1

When you do that, and the inner class is accessible to other classes (it's accessibility is Public or Friend), the outer class basically just works like a namespace. So for instance, using your example, you could create a new object of the nested class without ever creating one of the outer class:

Dim x As New FirstClass.SecondClass()

The most obvious benefit is the structural organization of the code, much like namespaces and code files. So, for instance, it's not uncommon to use nested classes for constants, to help better organize them:

Public Class Urls
    Public Class Processing
        Public Const Submit As String = "..."
        Public Const Cancel As String = "..."
    End Class

    Public Class Reporting
        Public Const Daily As String = "..."
        Public Const Weekly As String = "..."
    End Class
End Class

' ...

Dim url As String = Urls.Reporting.Daily

However, outside of the narrow set of situations where things like that are useful, most people would prefer to not nest public classes at all.

However, as others have mentioned, the one place where you really will see nested classes used fairly regularly is for Private ones. If you need some small helper class which will have no use to code outside of your class, there's no reason to expose it. Even if you set it's accessibility to Friend, it will still be visible to all the other classes in the same project. Therefore, if you really want to hide it from everything else, you'll want to make it a nested private class. For instance:

Public Class MyClass
    Public Function GetTheIdOfSomething() As Integer
        Dim d As Details = GetDetailsAboutSomething()
        If d.Value Is Nothing Then
            Return d.Id
        Else
            Throw New Exception()
        End If
    End Sub

    Private Function GetDetailsAboutSomething() As Details
        ' ... return a Details object
    End Function

    Private Class Details
        Public Property Id As Integer
        Public Property Value As String
    End Class
End Class
Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
  • "The most obvious benefit is the structural organization of the code, much like namespaces and code files." Interesting.. What would be the benefit of nesting classes within `Class` blocks, over nesting classes within `Namespace` blocks? – Ama Feb 07 '19 at 18:44
  • @Ama There isn't much difference, really, except that most people only import namespaces (even though you can import classes too). So, by putting it in nested classes, you might expect to see the full chain of nesting written out everywhere it's used, whereas for a namespace, it's much more common to import the namespace rather than fully qualifying the namespace. – Steven Doggart Feb 07 '19 at 18:48
  • I see, so I guess if the class and its nested classes are tighly related, then I should nest classes, but if not then I should include the before-nested class into a namesepce block so that they give the user the ability to import the namespace if they want to code in that fashion. – Ama Feb 07 '19 at 19:34
  • Yes. It sounds like you're on the right track. As others have implied, the nesting of private classes is relatively common. The nesting of public classes is odd and generally avoided, but it's still available as an option if you need it...and there are rare occasions where you end up being glad you can. – Steven Doggart Feb 07 '19 at 19:39