EzBlog

Blogs from the mind of Tim Price

My Links

Blog Stats

Article Categories

Archives

Building Strongly Typed Nested Collections Part 1

Building Strongly Typed Nested Collections Part 1

By Tim Price

 

Requirements

 

Microsoft® Visual Studio® .NET 2003

Microsoft® Visual Basic .NET

 

Introduction

 

When designing n-tier applications, it is wise to look carefully at all the options available and pay particular attention to the type of objects that your business logic layer will return to the client. This client could be either an ASP.Net web form, ASP.Net web service, a .Net desktop application or even a Smart Device, such as a Personal Digital Assistant (PDA).

 

One of the most efficient approaches is to create Strongly Typed Collection objects, which will be returned by the Business Logic layer.

 

A collection is a group of related items. You can create your own collections to manipulate objects. Collections are also, a good way for and application to keep track of objects, which it may need to dynamically create and/or destroy.

 

A Strongly typed collection is a collection that contains objects of a known type. To create either a writable or read-only collection your application must inherit from one of the two classes below:

 

 

A collection inherited from either of these classes also implements the following interfaces:

 

  • IList
    • Represents a collection of objects that can be individually accessed by index.
  • IEnumerable
    • Supports a simple iteration over a collection.

 

Because a class inherited from the CollectionBase class automatically implements the IList interface, you can bind it to a control just the same way you would bind a data view object. Due to the IList interface inheriting from the IEnumerable interface, we can use a For-Each loop. The IList interface also combines the ICollection interface, which gives it the features that we have come to expect from any .Net array such as Add, Remove, RemoveAt, IndexOf, Insert, Contains and Clear.

 

The business logic layer will always return a strongly typed collection and therefore, any type of client can consume it consistently. By returning strongly typed collection object from the business logic layer, we can provide a consistent interface into the business logic layer that is not only efficient in terms of memory overhead but, also reduces compilation and runtime errors.

 

This article will walk you through the process of creating strongly typed collection inherited from CollectionBase.

 

Collection Hierarchy

 

The collection hierarchy we will be creating is illustrated below.

 

 

Illustration 1

 

From this diagram we can see that the world is the top level object and all other objects are contained exposed by it. The world parent object contains a collection of Destination objects, this collection can hold anything from 1 to x number of Location objects. Each Location can either hold a collection of further Locations or a collection of Resorts.

 

List 1 illustrates how this collection maps to data in the real world. You can see that Europe is a member of the World collection and is defined as a Destination. Great Briton is a member of the Europe collection and is also defined as a Location. Note: Great Briton is a Location, it also contains a collection of Locations; England, Ireland, Scotland and Wales. Each of these Locations exposes a collection of resorts.

 

 

  • World
    • Europe – Destination
      • Great Briton – Location
        • England - Location
          • London - Resort
          • Blackpool - Resort
          • Etc
        • Ireland – Location
          • Dublin - Resort
          • Cork - Resort
          • Etc
        • Scotland – Location
          • Edinburgh - Resort
          • Glasgow - Resort
          • etc
        • Wales – Location
          • Cardiff - Resort
          • Llandudno - Resort
          • Etc
      • Spain
        • Italian Lakes - Location
          • Lake Como - Resort
          • Lake Maggiore - Resort
          • Etc
    • USA & Canada - Destination
      • USA East - Location
        • Boston - Resort
        • Chicago - Resort
        • Etc
      • USA West - Location
        • Las Vegas - Resort
        • Los Angeles - Resort

 

List 1

 

In fact even though each item is labelled as a Destination, Location or a Resort, you would be forgiven for thinking that we are going to create an object to describe each one individually, including a collection class for each one. What we are going to create, are just two classes one of them will be the strongly typed collection class and the other will be the object class that is contained and exposed by the collection class. The reason for this is whether we are talking about a Destination or a Resort their descriptions are exactly the same in terms of structure and definition.

 

That is to say they all have a name and contain a collection of other objects, which can contain one or more objects. If you refer back to List 1 you can see that a Destination is really just a place with a name and a collection of Locations. A Location is another place, with a name and a collection of resorts.

 

Class Definitions

 

Since everything in its singular form is a Place, we are going to start of by creating an object of type Place. Table 1, illustrates the properties that this class will expose publicly.

 

Place Class

Property Name

Data Type

Definition

 

Place_ID

Integer

The ID number of the place

Parent_ID

Integer

The ID number of the parent of this place

Name

String

The name of the place

Locations

Object

A collection of Places exposed as Locations

Resorts

Object

A collection of Resorts exposed as Resorts

 

 

 

 

 

 

 

 

Table 1

 

The only thing of any real interest here are Locations and Resorts. These are properties the return collections of Place objects, but labelled as Locations and Resorts respectively.

 

Table 2 shows the definition of the collection class that will hold all the Place objects.

 

Places Class

Property Name

Data Type

Definition

 

Item

Place object

The Place object located at the supplied index

Method Name/s

Data Type

Definition

 

Add

Place object

Adds a place object passed as a parameter

Remove

Place object

Removes a place object at the supplied index

New

Nothing

Class constructor

 

Table 2

 

You can see that this collection class is strongly typed by the fact that the property Item returns a Place object. The Add methods can only accept a Place object. The Remove method can only remove a Place object.

 

To return a Place object the Item property requires an integer to be passed to it, in order to locate the Place object from within the collection at the supplied index.

 

Creating the Place Class

 

The first things we need to create are the Private Member Variables. The variables are not visible to the outside world, and are used internally for data storage.

 

Public Class Place

 

#Region "Private Member Variables"

 

    Private m_iPlace_ID As Integer

    Private m_iParent_ID As Integer

    Private m_sName As String

    Private m_colLocations As Places

    Private m_colResorts As Places

 

#End Region

 

We now need to create the Public Properties. These properties are visible to the outside world and set or return the values of the Private Member Variables.

 

#Region "Public Properties"

 

    Public Property Place_ID() As Integer

        Get

            Return m_iPlace_ID

        End Get

        Set(ByVal Value As Integer)

            m_iPlace_ID = Value

        End Set

    End Property

 

    Public Property Parent_ID() As Integer

        Get

            Return m_iParent_ID

        End Get

        Set(ByVal Value As Integer)

            m_iParent_ID = Value

        End Set

    End Property

 

    Public Property Name() As String

        Get

            Return m_sName

        End Get

        Set(ByVal Value As String)

            m_sName = Value

        End Set

    End Property

 

    Public Property Locations() As Places

        Get

            Return m_colLocations

        End Get

        Set(ByVal Value As Places)

            m_colLocations = Value

        End Set

    End Property

 

    Public Property Resorts() As Places

        Get

            Return m_colResorts

        End Get

        Set(ByVal Value As Places)

            m_colResorts = Value

        End Set

    End Property

 

#End Region

 

End Class

 

Notice that the Locations and Resorts properties are really returning a Places collection.

 

Creating the Places Collection Class

 

To make this a collection class, we need to inherit the CollectionBase class which can be found in the System.Collections class.

 

Our first property will be a ReadOnly property that will return an object of type Place, which is located in the inner List object at the specified index.

 

The first method we need to create is Add which is a Public wrapper around the inner list objects Add method and provides us with a way of adding a Place object to the collection.

 

The next method is another wrapper and again is Public, which provides a way to remove a Place object from the collection. It implements the inner lists RemoveAt method, which accepts an integer value representing the index of the Place object in the collection to remove.

 

The final two methods are called New. Note: New is a reserved keyword which is used to create an instance of the class. For further information on the New keyword, see the following topics in MSDN:

 

 

The first New method accepts no parameters. The reason for this is because we are adding a second New method which will be an overloaded method and which does accept a parameter of type SqlDataReader. If we didn’t have the first empty method that accepted no parameters, we would get an Argument not specified error every time we wrote the following line of code in our client.

 

Dim oPlaces As New Places

 

We now have the option of creating a new Places collection by writing the above line of code, or, by writing the following line.

 

Dim oPlaces As New Places(ANEWDATAREADEROBJECT)

 

The SqlDataReader is used to populate the collection with values from the database. Note: To use the SqlClient class, we need to import it into our class file. Go to the very top of our class file and locate the following line of code.

 

Public Class Place

 

#Region "Private Member Variables"

      Etc...

 

 

And add the following imports statement to it.

 

Imports System.Data.SqlClient

 

OK, now we can continue defining our Collection Class.

 

Public Class Places

    Inherits System.Collections.CollectionBase

 

#Region "Public Properties"

 

    Public ReadOnly Property Item(ByVal iIndex As Integer) As Place

        Get

            Return CType(List.Item(iIndex), Place)

        End Get

    End Property

 

#End Region

 

#Region "Public Methods"

 

    Public Sub Add(ByVal oPlace As Place)

        List.Add(oPlace)

    End Sub

 

    Public Sub Remove(ByVal iIndex As Integer)

        List.RemoveAt(iIndex)

    End Sub

 

    Public Sub New()

 

    End Sub

 

    Public Sub New(ByVal oDataReader As SqlDataReader)

        Dim oPlace As Place

        While oDataReader.Read

            oPlace = New Place

            With oPlace

                .Place_ID = oDataReader.Item("Place_ID")

                .Parent_ID = oDataReader.Item("Parent_ID")

                .Name = oDataReader.Item("Name")

            End With

            Add(oPlace)

        End While

    End Sub

#End Region

 

End Class

 

 

Putting It All Together

 

You should now a single file that corresponds with the one below.

 

Imports System.Data.SqlClient

 

Public Class Place

 

#Region "Private Member Variables"

 

    Private m_iPlace_ID As Integer

    Private m_iParent_ID As Integer

    Private m_sName As String

    Private m_colLocations As Places

    Private m_colResorts As Places

 

#End Region

 

#Region "Public Properties"

 

    Public Property Place_ID() As Integer

        Get

            Return m_iPlace_ID

        End Get

        Set(ByVal Value As Integer)

            m_iPlace_ID = Value

        End Set

    End Property

 

    Public Property Parent_ID() As Integer

        Get

            Return m_iParent_ID

        End Get

        Set(ByVal Value As Integer)

            m_iParent_ID = Value

        End Set

    End Property

 

    Public Property Name() As String

        Get

            Return m_sName

        End Get

        Set(ByVal Value As String)

            m_sName = Value

        End Set

    End Property

 

    Public Property Locations() As Places