Nested Classes in Visual Basic.Net

The power and expressiveness of Visual Basic.Net represents a marked difference between versions 6 and 7 (VB.NET). The fundamental idioms have change moderately on the surface. The basic grammar has changed only a little making VB.NET code recognizable as Visual Basic. However, it is the more advanced idioms that have changed significantly, making VB.NET an expressive and powerful development language. One such idiom is the nested class. Visual Basic.Net supports nested classes. Although the nested class idiom is not a common-place idiom, nested classes do demonstrate on facet of the breadth and depth of changes in VB.NET that make it a first class language.

A nested class is quite simply a class defined within a class. Technically, wherever you can use a nested class you could use a non-nested class; thus the reason for employing the nested class idiom is a semantic reason. You can and would employ a nested class in VB.NET when you a body of code, including some number of methods, fields, properties, and events, that describe an entity in the solution domain and do not make sense outside of the enclosing class. You might also use a nested class if you need to capture multiple snapshots of state internally. Keep in mind that either of these problems can be implemented using every day aggregation relationships. Actually employing the nested class idiom is a semantic election and in this instance, demonstrates a new capability of Visual Basic.Net.

While writing this article a problem that naturally presents itself if how to model a book, perhaps for managing digital e-books. A book is comprised of a table of contents, index, perhaps a bibliography, and chapters. Each of these entities represents a class; further we could argue that none of these elements makes sense out of the context of book. Finally, in the case of the chapter, a book will likely contain multiple chapters. As a result table of contents, index, bibliography, and chapter all represent good classes, and chapters could be organized into a statically sized array or collection of chapter objects. Listing 1 demonstrates a solution to the e-book problem using VB.NET nested classes.

Listing 1: Implementing a solution for representing the relationship between a book and its contents.

1:  Public Class EBook
3:  #Region " Public Members "
5:    Public Property Title() As String
6:      Get
7:        Return FTitle
8:      End Get
9:      Set(ByVal Value As String)
10:       FTitle = Value
11:     End Set
12:   End Property
14:   Public ReadOnly Property Table() As String
15:     Get
16:       Return CType(Elements(0), TableofContents).Content
17:     End Get
18:   End Property
20:   Public Sub New()
21:     MyBase.New()
22:     Elements = New ArrayList()
23:     Elements.Add(New TableofContents("Table of Contents", ""))
24:   End Sub
26:   Public Sub Dispose()
27:     Static Disposed As Boolean = False
28:     If (Disposed) Then Exit Sub
29:     Disposed = True
30:     Elements = Nothing
31:   End Sub
33:   Private Sub Increment()
34:     If (FIndex < Elements.Count) Then
35:       FIndex += 1
36:     Else
37:       Beep()
38:     End If
39:   End Sub
41:   Public Function MoveNext() As Boolean
42:     Increment()
43:     Return FIndex < Elements.Count
44:   End Function
46:   Public Sub Reset()
47:     FIndex = -1
48:   End Sub
50:   Public ReadOnly Property ChapterTitle() As String
51:     Get
52:       Return Current.Title
53:     End Get
54:   End Property
56:   Public ReadOnly Property ChapterContent() As String
57:     Get
58:       Return Current.Content
59:     End Get
60:   End Property
62:   Private ReadOnly Property Current() As Chapter
63:     Get
64:       Return Elements(FIndex)
65:     End Get
66:   End Property
68:   Private Sub Decrement()
69:     If (FIndex > 1) Then
70:       FIndex -= 1
71:     Else
72:       Beep()
73:     End If
74:   End Sub
76:   Public Function MovePrevious() As Boolean
77:     Decrement()
78:     Return FIndex >= 0
79:   End Function
81:   Public Sub AddChapter(ByVal Title As String, _
82:     ByVal Content As String)
83:     Elements.Add(New Chapter(Title, Content))
84:     FIndex = Elements.Count
85:   End Sub
86: #End Region
88: #Region " Protected Members "
89:   Protected Overrides Sub Finalize()
90:     Dispose()
91:     MyBase.Finalize()
92:   End Sub
93: #End Region
95: #Region " Private Members "
96:   Private Elements As ArrayList
97:   Private FTitle As String
98:   Private FIndex As Long = 0
99: #End Region
101: #Region " Nested Classes "
103:   Protected MustInherit Class BookElement
104:     Protected FTitle As String
105:     Protected FContent As String
107:     Public Sub New()
108:       MyBase.New()
109:     End Sub
111:     Public Sub New(ByVal theTitle As String, _
112:       ByVal theContent As String)
114:       MyBase.New()
115:       FTitle = theTitle
116:       FContent = theContent
117:     End Sub
119:     Public ReadOnly Property Title() As String
120:       Get
121:         Return FTitle
122:       End Get
123:     End Property
125:     Public MustOverride ReadOnly Property Content() As String
127:     Public ReadOnly Property PageCount() As Integer
128:       Get
129:         Return GetPageCount()
130:       End Get
131:     End Property
133:     Private Function GetPageCount() As Integer
134:       Return Len(Content) / 500
135:     End Function
136:   End Class
138:   Protected Class Chapter
139:     Inherits BookElement
141:     Public Overrides ReadOnly Property Content() As String
142:       Get
143:         Return FContent
144:       End Get
145:     End Property
147:     Public Sub New(ByVal theTitle As String, _
148:       ByVal theContent As String)
150:       MyBase.New(theTitle, theContent)
151:     End Sub
153:   End Class
155:   Protected Class TableofContents
156:     Inherits BookElement
158:     Public Overrides ReadOnly Property Content() As String
159:       Get
160:         Return FContent
161:       End Get
162:     End Property
164:     Public Sub New()
165:       MyBase.New()
166:     End Sub
168:     Public Sub New(ByVal theTitle As String, _
169:       ByVal theContent As String)
170:       MyBase.New(theTitle, theContent)
171:     End Sub
173:     Public Sub AddHeader(ByVal Title As String)
174:       ' Add Element to Table of Contents
175:     End Sub
176:   End Class
178: #End Region
180: End Class

The listing is long, illustrating how nested classes can become quite long very quickly. To organize the class I used the #Region pragma to create outlined code regions. The EBook class is ordered by consumer interest. The public members are listed first followed by the protected, private, and nested members.

The nested elements of EBook are defined from lines 101 to 178. The first nested member is a nested abstract class BookElement. BookElements are defined to have an element title, some content, and span some number of pages. Two BookElement classes are defined: Chapter beginning on line 138 and TableOfContents beginning on line 155. Both Chapter and TableOfContents inherit from BookElement and must implement the abstract virtual property Content—on line 125—indicated by the MustOverride modifier. Implementing Content as a polymorphic property allows you to implement Content to return differently formatted text data. For example, TableOfContents might return text that is chapter titles with the appended starting page of the chapter, and the Contents property for a chapter might be formatted as Rich Text with page numbers. If you have a property or method with the MustOverride method then you must use the MustInherit class modifier, line 103. MustInherit classes are virtual abstract classes; virtual abstract classes are very similar to the intent of COM interfaces. A virtual abstract class is used to guide the implementation of child classes.

The EBook class is defined to internally manage chapters. When a consumer adds a chapter, a good implementation would be to update the TableofContents class and dynamically calculate page numbers based on the span of pages in the TableOfContents and all of the chapters.

There is a lot of extra code. We might want to move the navigation methods to a separate class of implement the IEnumerate interface. What should be apparent by the code listing is that Visual Basic.Net supports a diverse variety of idioms and allows you to write significantly more expressive code. Line 16 demonstrates dynamic type-checking. Lines 14 to 18 demonstrate a read only property. Check out lines 20 through 24 for an example of a VB.NET constructor, and Line 26 through 31 demonstrates a conventionally convenient Dispose method. An overloaded destructor is defined on lines 89 to 92. Lines 111 to 117 demonstrates a parameterized constructor.

Combining the new idioms and expanded grammar, Visual Basic.Net has a larger vocabulary, allowing your code to be more expressive. Finding a suitable balance between the new idioms, like nested classes, and aggressively managing code complexity is an implicit objective you with have to tackle.

About the Author

Paul Kimmel is a freelance writer for and He is the founder of Software Conceptions, Inc, founded in 1990. Paul Kimmel performs contract software development services in North America and can be contacted at


  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The open source cloud computing project OpenStack has come a long way since NASA and Rackspace launched it in 2010. Backed by leading technology infrastructure providers including Cisco, Dell, EMC, HP, IBM, Intel, and VMware, OpenStack underpins significant workloads at an increasingly diverse set of organizations, including BWM, CERN, Comcast, eBay, and Wal-Mart. For CIOs engaged in broader programs to win, serve, and retain customers -- and refocus business technology (BT) spend -- a planned and pragmatic …

  • Entire organizations suffer when their networks can't keep up and new opportunities are put on hold. Waiting on service providers isn't good business. In these examples, learn how to simplify network management so that your organization can better manage costs, adapt quickly to business demands, and seize market opportunities when they arise.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date